code refactor
This commit is contained in:
+2
-2
@@ -153,7 +153,7 @@ func startWebServer(c *cli.Context) error {
|
|||||||
router.StaticFile("/desktop/"+workboxFileNames[i], filepath.Join(config.StaticRootPath, workboxFileNames[i]))
|
router.StaticFile("/desktop/"+workboxFileNames[i], filepath.Join(config.StaticRootPath, workboxFileNames[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.AvatarProvider == settings.InternalAvatarProvider {
|
if config.AvatarProvider == core.USER_AVATAR_PROVIDER_INTERNAL {
|
||||||
avatarRoute := router.Group("/avatar")
|
avatarRoute := router.Group("/avatar")
|
||||||
avatarRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString))
|
avatarRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString))
|
||||||
{
|
{
|
||||||
@@ -261,7 +261,7 @@ func startWebServer(c *cli.Context) error {
|
|||||||
apiV1Route.GET("/users/profile/get.json", bindApi(api.Users.UserProfileHandler))
|
apiV1Route.GET("/users/profile/get.json", bindApi(api.Users.UserProfileHandler))
|
||||||
apiV1Route.POST("/users/profile/update.json", bindApiWithTokenUpdate(api.Users.UserUpdateProfileHandler, config))
|
apiV1Route.POST("/users/profile/update.json", bindApiWithTokenUpdate(api.Users.UserUpdateProfileHandler, config))
|
||||||
|
|
||||||
if config.AvatarProvider == settings.InternalAvatarProvider {
|
if config.AvatarProvider == core.USER_AVATAR_PROVIDER_INTERNAL {
|
||||||
apiV1Route.POST("/users/avatar/update.json", bindApi(api.Users.UserUpdateAvatarHandler))
|
apiV1Route.POST("/users/avatar/update.json", bindApi(api.Users.UserUpdateAvatarHandler))
|
||||||
apiV1Route.POST("/users/avatar/remove.json", bindApi(api.Users.UserRemoveAvatarHandler))
|
apiV1Route.POST("/users/avatar/remove.json", bindApi(api.Users.UserRemoveAvatarHandler))
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -16,12 +16,20 @@ import (
|
|||||||
|
|
||||||
// AccountsApi represents account api
|
// AccountsApi represents account api
|
||||||
type AccountsApi struct {
|
type AccountsApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
|
ApiUsingDuplicateChecker
|
||||||
accounts *services.AccountService
|
accounts *services.AccountService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize an account api singleton instance
|
// Initialize an account api singleton instance
|
||||||
var (
|
var (
|
||||||
Accounts = &AccountsApi{
|
Accounts = &AccountsApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
ApiUsingDuplicateChecker: ApiUsingDuplicateChecker{
|
||||||
|
container: duplicatechecker.Container,
|
||||||
|
},
|
||||||
accounts: services.Accounts,
|
accounts: services.Accounts,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -211,8 +219,8 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
mainAccount := a.createNewAccountModel(uid, &accountCreateReq, maxOrderId+1)
|
mainAccount := a.createNewAccountModel(uid, &accountCreateReq, maxOrderId+1)
|
||||||
childrenAccounts := a.createSubAccountModels(uid, &accountCreateReq)
|
childrenAccounts := a.createSubAccountModels(uid, &accountCreateReq)
|
||||||
|
|
||||||
if settings.Container.Current.EnableDuplicateSubmissionsCheck && accountCreateReq.ClientSessionId != "" {
|
if a.CurrentConfig().EnableDuplicateSubmissionsCheck && accountCreateReq.ClientSessionId != "" {
|
||||||
found, remark := duplicatechecker.Container.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_ACCOUNT, uid, accountCreateReq.ClientSessionId)
|
found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_ACCOUNT, uid, accountCreateReq.ClientSessionId)
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
log.InfofWithRequestId(c, "[accounts.AccountCreateHandler] another account \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
log.InfofWithRequestId(c, "[accounts.AccountCreateHandler] another account \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
||||||
@@ -256,7 +264,7 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
|
|
||||||
log.InfofWithRequestId(c, "[accounts.AccountCreateHandler] user \"uid:%d\" has created a new account \"id:%d\" successfully", uid, mainAccount.AccountId)
|
log.InfofWithRequestId(c, "[accounts.AccountCreateHandler] user \"uid:%d\" has created a new account \"id:%d\" successfully", uid, mainAccount.AccountId)
|
||||||
|
|
||||||
duplicatechecker.Container.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_ACCOUNT, uid, accountCreateReq.ClientSessionId, utils.Int64ToString(mainAccount.AccountId))
|
a.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_ACCOUNT, uid, accountCreateReq.ClientSessionId, utils.Int64ToString(mainAccount.AccountId))
|
||||||
accountInfoResp := mainAccount.ToAccountInfoResponse()
|
accountInfoResp := mainAccount.ToAccountInfoResponse()
|
||||||
|
|
||||||
if len(childrenAccounts) > 0 {
|
if len(childrenAccounts) > 0 {
|
||||||
|
|||||||
@@ -18,11 +18,16 @@ const amapRestApiUrl = "https://restapi.amap.com/"
|
|||||||
|
|
||||||
// AmapApiProxy represents amap api proxy
|
// AmapApiProxy represents amap api proxy
|
||||||
type AmapApiProxy struct {
|
type AmapApiProxy struct {
|
||||||
|
ApiUsingConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a amap api proxy singleton instance
|
// Initialize a amap api proxy singleton instance
|
||||||
var (
|
var (
|
||||||
AmapApis = &AmapApiProxy{}
|
AmapApis = &AmapApiProxy{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// AmapApiProxyHandler returns amap api response
|
// AmapApiProxyHandler returns amap api response
|
||||||
@@ -38,7 +43,7 @@ func (p *AmapApiProxy) AmapApiProxyHandler(c *core.Context) (*httputil.ReversePr
|
|||||||
}
|
}
|
||||||
|
|
||||||
director := func(req *http.Request) {
|
director := func(req *http.Request) {
|
||||||
targetRawUrl := fmt.Sprintf("%s?%s&jscode=%s", targetUrl, req.URL.RawQuery, settings.Container.Current.AmapApplicationSecret)
|
targetRawUrl := fmt.Sprintf("%s?%s&jscode=%s", targetUrl, req.URL.RawQuery, p.CurrentConfig().AmapApplicationSecret)
|
||||||
targetUrl, _ := url.Parse(targetRawUrl)
|
targetUrl, _ := url.Parse(targetRawUrl)
|
||||||
|
|
||||||
oldCookies := req.Cookies()
|
oldCookies := req.Cookies()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
// AuthorizationsApi represents authorization api
|
// AuthorizationsApi represents authorization api
|
||||||
type AuthorizationsApi struct {
|
type AuthorizationsApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
users *services.UserService
|
users *services.UserService
|
||||||
tokens *services.TokenService
|
tokens *services.TokenService
|
||||||
twoFactorAuthorizations *services.TwoFactorAuthorizationService
|
twoFactorAuthorizations *services.TwoFactorAuthorizationService
|
||||||
@@ -21,6 +22,9 @@ type AuthorizationsApi struct {
|
|||||||
// Initialize a authorization api singleton instance
|
// Initialize a authorization api singleton instance
|
||||||
var (
|
var (
|
||||||
Authorizations = &AuthorizationsApi{
|
Authorizations = &AuthorizationsApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
users: services.Users,
|
users: services.Users,
|
||||||
tokens: services.Tokens,
|
tokens: services.Tokens,
|
||||||
twoFactorAuthorizations: services.TwoFactorAuthorizations,
|
twoFactorAuthorizations: services.TwoFactorAuthorizations,
|
||||||
@@ -49,7 +53,7 @@ func (a *AuthorizationsApi) AuthorizeHandler(c *core.Context) (any, *errs.Error)
|
|||||||
return nil, errs.ErrUserIsDisabled
|
return nil, errs.ErrUserIsDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
if a.CurrentConfig().EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||||
hasValidEmailVerifyToken, err := a.tokens.ExistsValidTokenByType(c, user.Uid, core.USER_TOKEN_TYPE_EMAIL_VERIFY)
|
hasValidEmailVerifyToken, err := a.tokens.ExistsValidTokenByType(c, user.Uid, core.USER_TOKEN_TYPE_EMAIL_VERIFY)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -143,7 +147,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeHandler(c *core.Context) (any, *er
|
|||||||
return nil, errs.ErrUserIsDisabled
|
return nil, errs.ErrUserIsDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
if a.CurrentConfig().EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
}
|
}
|
||||||
@@ -205,7 +209,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
|
|||||||
return nil, errs.ErrUserIsDisabled
|
return nil, errs.ErrUserIsDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableUserForceVerifyEmail && !user.EmailVerified {
|
if a.CurrentConfig().EnableUserForceVerifyEmail && !user.EmailVerified {
|
||||||
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.WarnfWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
}
|
}
|
||||||
@@ -244,7 +248,7 @@ func (a *AuthorizationsApi) getAuthResponse(c *core.Context, token string, need2
|
|||||||
return &models.AuthResponse{
|
return &models.AuthResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
Need2FA: need2FA,
|
Need2FA: need2FA,
|
||||||
User: user.ToUserBasicInfo(),
|
User: a.GetUserBasicInfo(user),
|
||||||
NotificationContent: settings.Container.GetAfterLoginNotificationContent(user.Language, c.GetClientLocale()),
|
NotificationContent: a.GetAfterLoginNotificationContent(user.Language, c.GetClientLocale()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/duplicatechecker"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApiUsingConfig represents an api that need to use config
|
||||||
|
type ApiUsingConfig struct {
|
||||||
|
container *settings.ConfigContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentConfig returns the current config
|
||||||
|
func (a *ApiUsingConfig) CurrentConfig() *settings.Config {
|
||||||
|
return a.container.Current
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserBasicInfo returns the view-object of user basic info according to the user model
|
||||||
|
func (a *ApiUsingConfig) GetUserBasicInfo(user *models.User) *models.UserBasicInfo {
|
||||||
|
return user.ToUserBasicInfo(a.CurrentConfig().AvatarProvider, a.CurrentConfig().RootUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAfterRegisterNotificationContent returns the notification content displayed each time users register
|
||||||
|
func (a *ApiUsingConfig) GetAfterRegisterNotificationContent(userLanguage string, clientLanguage string) string {
|
||||||
|
language := userLanguage
|
||||||
|
|
||||||
|
if language == "" {
|
||||||
|
language = clientLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.container.Current.AfterRegisterNotification.Enabled {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if multiLanguageContent, exists := a.container.Current.AfterRegisterNotification.MultiLanguageContent[language]; exists {
|
||||||
|
return multiLanguageContent
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.container.Current.AfterRegisterNotification.DefaultContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAfterLoginNotificationContent returns the notification content displayed each time users log in
|
||||||
|
func (a *ApiUsingConfig) GetAfterLoginNotificationContent(userLanguage string, clientLanguage string) string {
|
||||||
|
language := userLanguage
|
||||||
|
|
||||||
|
if language == "" {
|
||||||
|
language = clientLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.container.Current.AfterLoginNotification.Enabled {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if multiLanguageContent, exists := a.container.Current.AfterLoginNotification.MultiLanguageContent[language]; exists {
|
||||||
|
return multiLanguageContent
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.container.Current.AfterLoginNotification.DefaultContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAfterOpenNotificationContent returns the notification content displayed each time users open the app
|
||||||
|
func (a *ApiUsingConfig) GetAfterOpenNotificationContent(userLanguage string, clientLanguage string) string {
|
||||||
|
language := userLanguage
|
||||||
|
|
||||||
|
if language == "" {
|
||||||
|
language = clientLanguage
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.container.Current.AfterOpenNotification.Enabled {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if multiLanguageContent, exists := a.container.Current.AfterOpenNotification.MultiLanguageContent[language]; exists {
|
||||||
|
return multiLanguageContent
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.container.Current.AfterOpenNotification.DefaultContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApiUsingDuplicateChecker represents an api that need to use duplicate checker
|
||||||
|
type ApiUsingDuplicateChecker struct {
|
||||||
|
container *duplicatechecker.DuplicateCheckerContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubmissionRemark returns whether the same submission has been processed and related remark by the current duplicate checker
|
||||||
|
func (a *ApiUsingDuplicateChecker) GetSubmissionRemark(checkerType duplicatechecker.DuplicateCheckerType, uid int64, identification string) (bool, string) {
|
||||||
|
return a.container.GetSubmissionRemark(checkerType, uid, identification)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSubmissionRemark saves the identification and remark to in-memory cache by the current duplicate checker
|
||||||
|
func (a *ApiUsingDuplicateChecker) SetSubmissionRemark(checkerType duplicatechecker.DuplicateCheckerType, uid int64, identification string, remark string) {
|
||||||
|
a.container.SetSubmissionRemark(checkerType, uid, identification, remark)
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ const pageCountForDataExport = 1000
|
|||||||
|
|
||||||
// DataManagementsApi represents data management api
|
// DataManagementsApi represents data management api
|
||||||
type DataManagementsApi struct {
|
type DataManagementsApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
ezBookKeepingCsvExporter *converters.EzBookKeepingCSVFileExporter
|
ezBookKeepingCsvExporter *converters.EzBookKeepingCSVFileExporter
|
||||||
ezBookKeepingTsvExporter *converters.EzBookKeepingTSVFileExporter
|
ezBookKeepingTsvExporter *converters.EzBookKeepingTSVFileExporter
|
||||||
tokens *services.TokenService
|
tokens *services.TokenService
|
||||||
@@ -33,6 +34,9 @@ type DataManagementsApi struct {
|
|||||||
// Initialize a data management api singleton instance
|
// Initialize a data management api singleton instance
|
||||||
var (
|
var (
|
||||||
DataManagements = &DataManagementsApi{
|
DataManagements = &DataManagementsApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
ezBookKeepingCsvExporter: &converters.EzBookKeepingCSVFileExporter{},
|
ezBookKeepingCsvExporter: &converters.EzBookKeepingCSVFileExporter{},
|
||||||
ezBookKeepingTsvExporter: &converters.EzBookKeepingTSVFileExporter{},
|
ezBookKeepingTsvExporter: &converters.EzBookKeepingTSVFileExporter{},
|
||||||
tokens: services.Tokens,
|
tokens: services.Tokens,
|
||||||
@@ -162,7 +166,7 @@ func (a *DataManagementsApi) ClearDataHandler(c *core.Context) (any, *errs.Error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *DataManagementsApi) getExportedFileContent(c *core.Context, fileType string) ([]byte, string, *errs.Error) {
|
func (a *DataManagementsApi) getExportedFileContent(c *core.Context, fileType string) ([]byte, string, *errs.Error) {
|
||||||
if !settings.Container.Current.EnableDataExport {
|
if !a.CurrentConfig().EnableDataExport {
|
||||||
return nil, "", errs.ErrDataExportNotAllowed
|
return nil, "", errs.ErrDataExportNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ExchangeRatesApi represents exchange rate api
|
// ExchangeRatesApi represents exchange rate api
|
||||||
type ExchangeRatesApi struct{}
|
type ExchangeRatesApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize a exchange rate api singleton instance
|
// Initialize a exchange rate api singleton instance
|
||||||
var (
|
var (
|
||||||
ExchangeRates = &ExchangeRatesApi{}
|
ExchangeRates = &ExchangeRatesApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// LatestExchangeRateHandler returns latest exchange rate data
|
// LatestExchangeRateHandler returns latest exchange rate data
|
||||||
@@ -36,9 +42,9 @@ func (a *ExchangeRatesApi) LatestExchangeRateHandler(c *core.Context) (any, *err
|
|||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
|
|
||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
utils.SetProxyUrl(transport, settings.Container.Current.ExchangeRatesProxy)
|
utils.SetProxyUrl(transport, a.CurrentConfig().ExchangeRatesProxy)
|
||||||
|
|
||||||
if settings.Container.Current.ExchangeRatesSkipTLSVerify {
|
if a.CurrentConfig().ExchangeRatesSkipTLSVerify {
|
||||||
transport.TLSClientConfig = &tls.Config{
|
transport.TLSClientConfig = &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
@@ -46,7 +52,7 @@ func (a *ExchangeRatesApi) LatestExchangeRateHandler(c *core.Context) (any, *err
|
|||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
Timeout: time.Duration(settings.Container.Current.ExchangeRatesRequestTimeout) * time.Millisecond,
|
Timeout: time.Duration(a.CurrentConfig().ExchangeRatesRequestTimeout) * time.Millisecond,
|
||||||
}
|
}
|
||||||
|
|
||||||
urls := dataSource.GetRequestUrls()
|
urls := dataSource.GetRequestUrls()
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
// ForgetPasswordsApi represents user forget password api
|
// ForgetPasswordsApi represents user forget password api
|
||||||
type ForgetPasswordsApi struct {
|
type ForgetPasswordsApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
users *services.UserService
|
users *services.UserService
|
||||||
tokens *services.TokenService
|
tokens *services.TokenService
|
||||||
forgetPasswords *services.ForgetPasswordService
|
forgetPasswords *services.ForgetPasswordService
|
||||||
@@ -21,6 +22,9 @@ type ForgetPasswordsApi struct {
|
|||||||
// Initialize a user api singleton instance
|
// Initialize a user api singleton instance
|
||||||
var (
|
var (
|
||||||
ForgetPasswords = &ForgetPasswordsApi{
|
ForgetPasswords = &ForgetPasswordsApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
users: services.Users,
|
users: services.Users,
|
||||||
tokens: services.Tokens,
|
tokens: services.Tokens,
|
||||||
forgetPasswords: services.ForgetPasswords,
|
forgetPasswords: services.ForgetPasswords,
|
||||||
@@ -52,12 +56,12 @@ func (a *ForgetPasswordsApi) UserForgetPasswordRequestHandler(c *core.Context) (
|
|||||||
return nil, errs.ErrUserIsDisabled
|
return nil, errs.ErrUserIsDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||||
log.WarnfWithRequestId(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.WarnfWithRequestId(c, "[forget_passwords.UserForgetPasswordRequestHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
if !settings.Container.Current.EnableSMTP {
|
if !a.CurrentConfig().EnableSMTP {
|
||||||
return nil, errs.ErrSMTPServerNotEnabled
|
return nil, errs.ErrSMTPServerNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +109,7 @@ func (a *ForgetPasswordsApi) UserResetPasswordHandler(c *core.Context) (any, *er
|
|||||||
return nil, errs.ErrUserIsDisabled
|
return nil, errs.ErrUserIsDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
if a.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||||
log.WarnfWithRequestId(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
log.WarnfWithRequestId(c, "[forget_passwords.UserResetPasswordHandler] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return nil, errs.ErrEmailIsNotVerified
|
return nil, errs.ErrEmailIsNotVerified
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,16 @@ const tianDiTuMapAnnotationUrlFormat = "https://t0.tianditu.gov.cn/cva_w/wmts?SE
|
|||||||
|
|
||||||
// MapImageProxy represents map image proxy
|
// MapImageProxy represents map image proxy
|
||||||
type MapImageProxy struct {
|
type MapImageProxy struct {
|
||||||
|
ApiUsingConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a map image proxy singleton instance
|
// Initialize a map image proxy singleton instance
|
||||||
var (
|
var (
|
||||||
MapImages = &MapImageProxy{}
|
MapImages = &MapImageProxy{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MapTileImageProxyHandler returns map tile image
|
// MapTileImageProxyHandler returns map tile image
|
||||||
@@ -47,7 +52,7 @@ func (p *MapImageProxy) MapTileImageProxyHandler(c *core.Context) (*httputil.Rev
|
|||||||
} else if mapProvider == settings.CartoDBMapProvider {
|
} else if mapProvider == settings.CartoDBMapProvider {
|
||||||
return cartoDBMapTileImageUrlFormat, nil
|
return cartoDBMapTileImageUrlFormat, nil
|
||||||
} else if mapProvider == settings.TomTomMapProvider {
|
} else if mapProvider == settings.TomTomMapProvider {
|
||||||
targetUrl := tomtomMapTileImageUrlFormat + "?key=" + settings.Container.Current.TomTomMapAPIKey
|
targetUrl := tomtomMapTileImageUrlFormat + "?key=" + p.CurrentConfig().TomTomMapAPIKey
|
||||||
language := c.Query("language")
|
language := c.Query("language")
|
||||||
|
|
||||||
if language != "" {
|
if language != "" {
|
||||||
@@ -56,9 +61,9 @@ func (p *MapImageProxy) MapTileImageProxyHandler(c *core.Context) (*httputil.Rev
|
|||||||
|
|
||||||
return targetUrl, nil
|
return targetUrl, nil
|
||||||
} else if mapProvider == settings.TianDiTuProvider {
|
} else if mapProvider == settings.TianDiTuProvider {
|
||||||
return tianDiTuMapTileImageUrlFormat + "&tk=" + settings.Container.Current.TianDiTuAPIKey, nil
|
return tianDiTuMapTileImageUrlFormat + "&tk=" + p.CurrentConfig().TianDiTuAPIKey, nil
|
||||||
} else if mapProvider == settings.CustomProvider {
|
} else if mapProvider == settings.CustomProvider {
|
||||||
return settings.Container.Current.CustomMapTileServerTileLayerUrl, nil
|
return p.CurrentConfig().CustomMapTileServerTileLayerUrl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errs.ErrParameterInvalid
|
return "", errs.ErrParameterInvalid
|
||||||
@@ -69,9 +74,9 @@ func (p *MapImageProxy) MapTileImageProxyHandler(c *core.Context) (*httputil.Rev
|
|||||||
func (p *MapImageProxy) MapAnnotationImageProxyHandler(c *core.Context) (*httputil.ReverseProxy, *errs.Error) {
|
func (p *MapImageProxy) MapAnnotationImageProxyHandler(c *core.Context) (*httputil.ReverseProxy, *errs.Error) {
|
||||||
return p.mapImageProxyHandler(c, func(c *core.Context, mapProvider string) (string, *errs.Error) {
|
return p.mapImageProxyHandler(c, func(c *core.Context, mapProvider string) (string, *errs.Error) {
|
||||||
if mapProvider == settings.TianDiTuProvider {
|
if mapProvider == settings.TianDiTuProvider {
|
||||||
return tianDiTuMapAnnotationUrlFormat + "&tk=" + settings.Container.Current.TianDiTuAPIKey, nil
|
return tianDiTuMapAnnotationUrlFormat + "&tk=" + p.CurrentConfig().TianDiTuAPIKey, nil
|
||||||
} else if mapProvider == settings.CustomProvider {
|
} else if mapProvider == settings.CustomProvider {
|
||||||
return settings.Container.Current.CustomMapTileServerAnnotationLayerUrl, nil
|
return p.CurrentConfig().CustomMapTileServerAnnotationLayerUrl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errs.ErrParameterInvalid
|
return "", errs.ErrParameterInvalid
|
||||||
@@ -82,7 +87,7 @@ func (p *MapImageProxy) mapImageProxyHandler(c *core.Context, fn func(c *core.Co
|
|||||||
mapProvider := strings.Replace(c.Query("provider"), "-", "_", -1)
|
mapProvider := strings.Replace(c.Query("provider"), "-", "_", -1)
|
||||||
targetUrl := ""
|
targetUrl := ""
|
||||||
|
|
||||||
if mapProvider != settings.Container.Current.MapProvider {
|
if mapProvider != p.CurrentConfig().MapProvider {
|
||||||
return nil, errs.ErrMapProviderNotCurrent
|
return nil, errs.ErrMapProviderNotCurrent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ func (p *MapImageProxy) mapImageProxyHandler(c *core.Context, fn func(c *core.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
utils.SetProxyUrl(transport, settings.Container.Current.MapProxy)
|
utils.SetProxyUrl(transport, p.CurrentConfig().MapProxy)
|
||||||
|
|
||||||
director := func(req *http.Request) {
|
director := func(req *http.Request) {
|
||||||
imageRawUrl := targetUrl
|
imageRawUrl := targetUrl
|
||||||
|
|||||||
+7
-2
@@ -19,16 +19,21 @@ const (
|
|||||||
|
|
||||||
// QrCodesApi represents qrcode generator api
|
// QrCodesApi represents qrcode generator api
|
||||||
type QrCodesApi struct {
|
type QrCodesApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a qrcode generator api singleton instance
|
// Initialize a qrcode generator api singleton instance
|
||||||
var (
|
var (
|
||||||
QrCodes = &QrCodesApi{}
|
QrCodes = &QrCodesApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MobileUrlQrCodeHandler returns a mobile url qr code image
|
// MobileUrlQrCodeHandler returns a mobile url qr code image
|
||||||
func (a *QrCodesApi) MobileUrlQrCodeHandler(c *core.Context) ([]byte, string, *errs.Error) {
|
func (a *QrCodesApi) MobileUrlQrCodeHandler(c *core.Context) ([]byte, string, *errs.Error) {
|
||||||
fullUrl := settings.Container.Current.RootUrl + "mobile"
|
fullUrl := a.CurrentConfig().RootUrl + "mobile"
|
||||||
data, err := a.generateUrlQrCode(c, fullUrl)
|
data, err := a.generateUrlQrCode(c, fullUrl)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+9
-5
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
// TokensApi represents token api
|
// TokensApi represents token api
|
||||||
type TokensApi struct {
|
type TokensApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
tokens *services.TokenService
|
tokens *services.TokenService
|
||||||
users *services.UserService
|
users *services.UserService
|
||||||
}
|
}
|
||||||
@@ -22,6 +23,9 @@ type TokensApi struct {
|
|||||||
// Initialize a token api singleton instance
|
// Initialize a token api singleton instance
|
||||||
var (
|
var (
|
||||||
Tokens = &TokensApi{
|
Tokens = &TokensApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
tokens: services.Tokens,
|
tokens: services.Tokens,
|
||||||
users: services.Users,
|
users: services.Users,
|
||||||
}
|
}
|
||||||
@@ -180,7 +184,7 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
oldTokenClaims := c.GetTokenClaims()
|
oldTokenClaims := c.GetTokenClaims()
|
||||||
|
|
||||||
if now-oldTokenClaims.IssuedAt < int64(settings.Container.Current.TokenMinRefreshInterval) {
|
if now-oldTokenClaims.IssuedAt < int64(a.CurrentConfig().TokenMinRefreshInterval) {
|
||||||
log.InfofWithRequestId(c, "[token.TokenRefreshHandler] token of user \"uid:%d\" does not need to be refreshed", uid)
|
log.InfofWithRequestId(c, "[token.TokenRefreshHandler] token of user \"uid:%d\" does not need to be refreshed", uid)
|
||||||
|
|
||||||
userTokenId, err := utils.StringToInt64(oldTokenClaims.UserTokenId)
|
userTokenId, err := utils.StringToInt64(oldTokenClaims.UserTokenId)
|
||||||
@@ -204,8 +208,8 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshResp := &models.TokenRefreshResponse{
|
refreshResp := &models.TokenRefreshResponse{
|
||||||
User: user.ToUserBasicInfo(),
|
User: a.GetUserBasicInfo(user),
|
||||||
NotificationContent: settings.Container.GetAfterOpenNotificationContent(user.Language, c.GetClientLocale()),
|
NotificationContent: a.GetAfterOpenNotificationContent(user.Language, c.GetClientLocale()),
|
||||||
}
|
}
|
||||||
|
|
||||||
return refreshResp, nil
|
return refreshResp, nil
|
||||||
@@ -233,8 +237,8 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
refreshResp := &models.TokenRefreshResponse{
|
refreshResp := &models.TokenRefreshResponse{
|
||||||
NewToken: token,
|
NewToken: token,
|
||||||
OldTokenId: a.tokens.GenerateTokenId(oldTokenRecord),
|
OldTokenId: a.tokens.GenerateTokenId(oldTokenRecord),
|
||||||
User: user.ToUserBasicInfo(),
|
User: a.GetUserBasicInfo(user),
|
||||||
NotificationContent: settings.Container.GetAfterOpenNotificationContent(user.Language, c.GetClientLocale()),
|
NotificationContent: a.GetAfterOpenNotificationContent(user.Language, c.GetClientLocale()),
|
||||||
}
|
}
|
||||||
|
|
||||||
return refreshResp, nil
|
return refreshResp, nil
|
||||||
|
|||||||
@@ -17,12 +17,20 @@ import (
|
|||||||
|
|
||||||
// TransactionCategoriesApi represents transaction category api
|
// TransactionCategoriesApi represents transaction category api
|
||||||
type TransactionCategoriesApi struct {
|
type TransactionCategoriesApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
|
ApiUsingDuplicateChecker
|
||||||
categories *services.TransactionCategoryService
|
categories *services.TransactionCategoryService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a transaction category api singleton instance
|
// Initialize a transaction category api singleton instance
|
||||||
var (
|
var (
|
||||||
TransactionCategories = &TransactionCategoriesApi{
|
TransactionCategories = &TransactionCategoriesApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
ApiUsingDuplicateChecker: ApiUsingDuplicateChecker{
|
||||||
|
container: duplicatechecker.Container,
|
||||||
|
},
|
||||||
categories: services.TransactionCategories,
|
categories: services.TransactionCategories,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -122,8 +130,8 @@ func (a *TransactionCategoriesApi) CategoryCreateHandler(c *core.Context) (any,
|
|||||||
|
|
||||||
category := a.createNewCategoryModel(uid, &categoryCreateReq, maxOrderId+1)
|
category := a.createNewCategoryModel(uid, &categoryCreateReq, maxOrderId+1)
|
||||||
|
|
||||||
if settings.Container.Current.EnableDuplicateSubmissionsCheck && categoryCreateReq.ClientSessionId != "" {
|
if a.CurrentConfig().EnableDuplicateSubmissionsCheck && categoryCreateReq.ClientSessionId != "" {
|
||||||
found, remark := duplicatechecker.Container.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_CATEGORY, uid, categoryCreateReq.ClientSessionId)
|
found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_CATEGORY, uid, categoryCreateReq.ClientSessionId)
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
log.InfofWithRequestId(c, "[transaction_categories.CategoryCreateHandler] another category \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
log.InfofWithRequestId(c, "[transaction_categories.CategoryCreateHandler] another category \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
||||||
@@ -153,7 +161,7 @@ func (a *TransactionCategoriesApi) CategoryCreateHandler(c *core.Context) (any,
|
|||||||
|
|
||||||
log.InfofWithRequestId(c, "[transaction_categories.CategoryCreateHandler] user \"uid:%d\" has created a new category \"id:%d\" successfully", uid, category.CategoryId)
|
log.InfofWithRequestId(c, "[transaction_categories.CategoryCreateHandler] user \"uid:%d\" has created a new category \"id:%d\" successfully", uid, category.CategoryId)
|
||||||
|
|
||||||
duplicatechecker.Container.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_CATEGORY, uid, categoryCreateReq.ClientSessionId, utils.Int64ToString(category.CategoryId))
|
a.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_CATEGORY, uid, categoryCreateReq.ClientSessionId, utils.Int64ToString(category.CategoryId))
|
||||||
categoryResp := category.ToTransactionCategoryInfoResponse()
|
categoryResp := category.ToTransactionCategoryInfoResponse()
|
||||||
|
|
||||||
return categoryResp, nil
|
return categoryResp, nil
|
||||||
|
|||||||
@@ -16,12 +16,20 @@ import (
|
|||||||
|
|
||||||
// TransactionTemplatesApi represents transaction template api
|
// TransactionTemplatesApi represents transaction template api
|
||||||
type TransactionTemplatesApi struct {
|
type TransactionTemplatesApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
|
ApiUsingDuplicateChecker
|
||||||
templates *services.TransactionTemplateService
|
templates *services.TransactionTemplateService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a transaction template api singleton instance
|
// Initialize a transaction template api singleton instance
|
||||||
var (
|
var (
|
||||||
TransactionTemplates = &TransactionTemplatesApi{
|
TransactionTemplates = &TransactionTemplatesApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
ApiUsingDuplicateChecker: ApiUsingDuplicateChecker{
|
||||||
|
container: duplicatechecker.Container,
|
||||||
|
},
|
||||||
templates: services.TransactionTemplates,
|
templates: services.TransactionTemplates,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -117,8 +125,8 @@ func (a *TransactionTemplatesApi) TemplateCreateHandler(c *core.Context) (any, *
|
|||||||
serverUtcOffset := utils.GetServerTimezoneOffsetMinutes()
|
serverUtcOffset := utils.GetServerTimezoneOffsetMinutes()
|
||||||
template := a.createNewTemplateModel(uid, &templateCreateReq, maxOrderId+1)
|
template := a.createNewTemplateModel(uid, &templateCreateReq, maxOrderId+1)
|
||||||
|
|
||||||
if settings.Container.Current.EnableDuplicateSubmissionsCheck && templateCreateReq.ClientSessionId != "" {
|
if a.CurrentConfig().EnableDuplicateSubmissionsCheck && templateCreateReq.ClientSessionId != "" {
|
||||||
found, remark := duplicatechecker.Container.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE, uid, templateCreateReq.ClientSessionId)
|
found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE, uid, templateCreateReq.ClientSessionId)
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
log.InfofWithRequestId(c, "[transaction_templates.TemplateCreateHandler] another template \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
log.InfofWithRequestId(c, "[transaction_templates.TemplateCreateHandler] another template \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
||||||
@@ -148,7 +156,7 @@ func (a *TransactionTemplatesApi) TemplateCreateHandler(c *core.Context) (any, *
|
|||||||
|
|
||||||
log.InfofWithRequestId(c, "[transaction_templates.TemplateCreateHandler] user \"uid:%d\" has created a new template \"id:%d\" successfully", uid, template.TemplateId)
|
log.InfofWithRequestId(c, "[transaction_templates.TemplateCreateHandler] user \"uid:%d\" has created a new template \"id:%d\" successfully", uid, template.TemplateId)
|
||||||
|
|
||||||
duplicatechecker.Container.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE, uid, templateCreateReq.ClientSessionId, utils.Int64ToString(template.TemplateId))
|
a.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE, uid, templateCreateReq.ClientSessionId, utils.Int64ToString(template.TemplateId))
|
||||||
templateResp := template.ToTransactionTemplateInfoResponse(serverUtcOffset)
|
templateResp := template.ToTransactionTemplateInfoResponse(serverUtcOffset)
|
||||||
|
|
||||||
return templateResp, nil
|
return templateResp, nil
|
||||||
|
|||||||
+11
-3
@@ -18,6 +18,8 @@ import (
|
|||||||
|
|
||||||
// TransactionsApi represents transaction api
|
// TransactionsApi represents transaction api
|
||||||
type TransactionsApi struct {
|
type TransactionsApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
|
ApiUsingDuplicateChecker
|
||||||
transactions *services.TransactionService
|
transactions *services.TransactionService
|
||||||
transactionCategories *services.TransactionCategoryService
|
transactionCategories *services.TransactionCategoryService
|
||||||
transactionTags *services.TransactionTagService
|
transactionTags *services.TransactionTagService
|
||||||
@@ -28,6 +30,12 @@ type TransactionsApi struct {
|
|||||||
// Initialize a transaction api singleton instance
|
// Initialize a transaction api singleton instance
|
||||||
var (
|
var (
|
||||||
Transactions = &TransactionsApi{
|
Transactions = &TransactionsApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
|
ApiUsingDuplicateChecker: ApiUsingDuplicateChecker{
|
||||||
|
container: duplicatechecker.Container,
|
||||||
|
},
|
||||||
transactions: services.Transactions,
|
transactions: services.Transactions,
|
||||||
transactionCategories: services.TransactionCategories,
|
transactionCategories: services.TransactionCategories,
|
||||||
transactionTags: services.TransactionTags,
|
transactionTags: services.TransactionTags,
|
||||||
@@ -663,8 +671,8 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (any, *errs.
|
|||||||
return nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
|
return nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableDuplicateSubmissionsCheck && transactionCreateReq.ClientSessionId != "" {
|
if a.CurrentConfig().EnableDuplicateSubmissionsCheck && transactionCreateReq.ClientSessionId != "" {
|
||||||
found, remark := duplicatechecker.Container.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TRANSACTION, uid, transactionCreateReq.ClientSessionId)
|
found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TRANSACTION, uid, transactionCreateReq.ClientSessionId)
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
log.InfofWithRequestId(c, "[transactions.TransactionCreateHandler] another transaction \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
log.InfofWithRequestId(c, "[transactions.TransactionCreateHandler] another transaction \"id:%s\" has been created for user \"uid:%d\"", remark, uid)
|
||||||
@@ -694,7 +702,7 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (any, *errs.
|
|||||||
|
|
||||||
log.InfofWithRequestId(c, "[transactions.TransactionCreateHandler] user \"uid:%d\" has created a new transaction \"id:%d\" successfully", uid, transaction.TransactionId)
|
log.InfofWithRequestId(c, "[transactions.TransactionCreateHandler] user \"uid:%d\" has created a new transaction \"id:%d\" successfully", uid, transaction.TransactionId)
|
||||||
|
|
||||||
duplicatechecker.Container.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TRANSACTION, uid, transactionCreateReq.ClientSessionId, utils.Int64ToString(transaction.TransactionId))
|
a.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TRANSACTION, uid, transactionCreateReq.ClientSessionId, utils.Int64ToString(transaction.TransactionId))
|
||||||
transactionResp := transaction.ToTransactionInfoResponse(tagIds, transactionEditable)
|
transactionResp := transaction.ToTransactionInfoResponse(tagIds, transactionEditable)
|
||||||
|
|
||||||
return transactionResp, nil
|
return transactionResp, nil
|
||||||
|
|||||||
+32
-93
@@ -1,8 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -15,13 +13,13 @@ import (
|
|||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/services"
|
"github.com/mayswind/ezbookkeeping/pkg/services"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/storage"
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/validators"
|
"github.com/mayswind/ezbookkeeping/pkg/validators"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UsersApi represents user api
|
// UsersApi represents user api
|
||||||
type UsersApi struct {
|
type UsersApi struct {
|
||||||
|
ApiUsingConfig
|
||||||
users *services.UserService
|
users *services.UserService
|
||||||
tokens *services.TokenService
|
tokens *services.TokenService
|
||||||
accounts *services.AccountService
|
accounts *services.AccountService
|
||||||
@@ -30,6 +28,9 @@ type UsersApi struct {
|
|||||||
// Initialize a user api singleton instance
|
// Initialize a user api singleton instance
|
||||||
var (
|
var (
|
||||||
Users = &UsersApi{
|
Users = &UsersApi{
|
||||||
|
ApiUsingConfig: ApiUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
users: services.Users,
|
users: services.Users,
|
||||||
tokens: services.Tokens,
|
tokens: services.Tokens,
|
||||||
accounts: services.Accounts,
|
accounts: services.Accounts,
|
||||||
@@ -38,7 +39,7 @@ var (
|
|||||||
|
|
||||||
// UserRegisterHandler saves a new user by request parameters
|
// UserRegisterHandler saves a new user by request parameters
|
||||||
func (a *UsersApi) UserRegisterHandler(c *core.Context) (any, *errs.Error) {
|
func (a *UsersApi) UserRegisterHandler(c *core.Context) (any, *errs.Error) {
|
||||||
if !settings.Container.Current.EnableUserRegister {
|
if !a.CurrentConfig().EnableUserRegister {
|
||||||
return nil, errs.ErrUserRegistrationNotAllowed
|
return nil, errs.ErrUserRegistrationNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,14 +93,14 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
authResp := &models.RegisterResponse{
|
authResp := &models.RegisterResponse{
|
||||||
AuthResponse: models.AuthResponse{
|
AuthResponse: models.AuthResponse{
|
||||||
Need2FA: false,
|
Need2FA: false,
|
||||||
User: user.ToUserBasicInfo(),
|
User: a.GetUserBasicInfo(user),
|
||||||
NotificationContent: settings.Container.GetAfterRegisterNotificationContent(user.Language, c.GetClientLocale()),
|
NotificationContent: a.GetAfterRegisterNotificationContent(user.Language, c.GetClientLocale()),
|
||||||
},
|
},
|
||||||
NeedVerifyEmail: settings.Container.Current.EnableUserVerifyEmail && settings.Container.Current.EnableUserForceVerifyEmail,
|
NeedVerifyEmail: a.CurrentConfig().EnableUserVerifyEmail && a.CurrentConfig().EnableUserForceVerifyEmail,
|
||||||
PresetCategoriesSaved: presetCategoriesSaved,
|
PresetCategoriesSaved: presetCategoriesSaved,
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableUserVerifyEmail && settings.Container.Current.EnableSMTP {
|
if a.CurrentConfig().EnableUserVerifyEmail && a.CurrentConfig().EnableSMTP {
|
||||||
token, _, err := a.tokens.CreateEmailVerifyToken(c, user)
|
token, _, err := a.tokens.CreateEmailVerifyToken(c, user)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,7 +116,7 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.EnableUserForceVerifyEmail {
|
if a.CurrentConfig().EnableUserForceVerifyEmail {
|
||||||
return authResp, nil
|
return authResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +188,8 @@ func (a *UsersApi) UserEmailVerifyHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp.NewToken = token
|
resp.NewToken = token
|
||||||
resp.User = user.ToUserBasicInfo()
|
resp.User = a.GetUserBasicInfo(user)
|
||||||
resp.NotificationContent = settings.Container.GetAfterLoginNotificationContent(user.Language, c.GetClientLocale())
|
resp.NotificationContent = a.GetAfterLoginNotificationContent(user.Language, c.GetClientLocale())
|
||||||
|
|
||||||
c.SetTextualToken(token)
|
c.SetTextualToken(token)
|
||||||
c.SetTokenClaims(claims)
|
c.SetTokenClaims(claims)
|
||||||
@@ -212,7 +213,7 @@ func (a *UsersApi) UserProfileHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
return nil, errs.ErrUserNotFound
|
return nil, errs.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
userResp := user.ToUserProfileResponse()
|
userResp := a.getUserProfileResponse(user)
|
||||||
return userResp, nil
|
return userResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,10 +448,10 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (any, *errs.Error)
|
|||||||
log.InfofWithRequestId(c, "[users.UserUpdateProfileHandler] user \"uid:%d\" has updated successfully", user.Uid)
|
log.InfofWithRequestId(c, "[users.UserUpdateProfileHandler] user \"uid:%d\" has updated successfully", user.Uid)
|
||||||
|
|
||||||
resp := &models.UserProfileUpdateResponse{
|
resp := &models.UserProfileUpdateResponse{
|
||||||
User: user.ToUserBasicInfo(),
|
User: a.GetUserBasicInfo(user),
|
||||||
}
|
}
|
||||||
|
|
||||||
if emailSetToUnverified && settings.Container.Current.EnableUserVerifyEmail && settings.Container.Current.EnableSMTP {
|
if emailSetToUnverified && a.CurrentConfig().EnableUserVerifyEmail && a.CurrentConfig().EnableSMTP {
|
||||||
err = a.tokens.DeleteTokensByType(c, uid, core.USER_TOKEN_TYPE_EMAIL_VERIFY)
|
err = a.tokens.DeleteTokensByType(c, uid, core.USER_TOKEN_TYPE_EMAIL_VERIFY)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -547,32 +548,15 @@ func (a *UsersApi) UserUpdateAvatarHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
return nil, errs.ErrOperationFailed
|
return nil, errs.ErrOperationFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
defer avatarFile.Close()
|
err = a.users.UpdateUserAvatar(c, user.Uid, avatarFile, fileExtension, user.CustomAvatarType)
|
||||||
|
|
||||||
err = storage.Container.SaveAvatar(user.Uid, avatarFile, fileExtension)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[users.UserUpdateAvatarHandler] failed to save avatar file for user \"uid:%d\", because %s", user.Uid, err.Error())
|
log.ErrorfWithRequestId(c, "[users.UserUpdateAvatarHandler] failed to update avatar for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||||
return nil, errs.ErrOperationFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.users.UpdateUserAvatar(c, user.Uid, fileExtension)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserUpdateAvatarHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileExtension != user.CustomAvatarType && user.CustomAvatarType != "" {
|
|
||||||
err = storage.Container.DeleteAvatar(user.Uid, user.CustomAvatarType)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.WarnfWithRequestId(c, "[users.UserUpdateAvatarHandler] failed to delete old avatar with extension \"%s\" for user \"uid:%d\", because %s", user.CustomAvatarType, user.Uid, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user.CustomAvatarType = fileExtension
|
user.CustomAvatarType = fileExtension
|
||||||
userResp := user.ToUserProfileResponse()
|
userResp := a.getUserProfileResponse(user)
|
||||||
return userResp, nil
|
return userResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,39 +577,21 @@ func (a *UsersApi) UserRemoveAvatarHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
return nil, errs.ErrNothingWillBeUpdated
|
return nil, errs.ErrNothingWillBeUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
err = storage.Container.DeleteAvatar(user.Uid, user.CustomAvatarType)
|
err = a.users.RemoveUserAvatar(c, user.Uid, user.CustomAvatarType)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[users.UserRemoveAvatarHandler] failed to delete avatar file for user \"uid:%d\", because %s", user.Uid, err.Error())
|
log.ErrorfWithRequestId(c, "[users.UserRemoveAvatarHandler] failed to remove avatar for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||||
|
|
||||||
exists, err := storage.Container.ExistsAvatar(user.Uid, user.CustomAvatarType)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserRemoveAvatarHandler] failed to check whether avatar file exist for user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, errs.ErrOperationFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
if exists {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserRemoveAvatarHandler] failed to delete whether avatar file exist for user \"uid:%d\", the avatar file still exist", user.Uid)
|
|
||||||
return nil, errs.ErrOperationFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = a.users.UpdateUserAvatar(c, user.Uid, "")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserRemoveAvatarHandler] failed to update user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.CustomAvatarType = ""
|
user.CustomAvatarType = ""
|
||||||
userResp := user.ToUserProfileResponse()
|
userResp := a.getUserProfileResponse(user)
|
||||||
return userResp, nil
|
return userResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserSendVerifyEmailByUnloginUserHandler sends unlogin user verify email
|
// UserSendVerifyEmailByUnloginUserHandler sends unlogin user verify email
|
||||||
func (a *UsersApi) UserSendVerifyEmailByUnloginUserHandler(c *core.Context) (any, *errs.Error) {
|
func (a *UsersApi) UserSendVerifyEmailByUnloginUserHandler(c *core.Context) (any, *errs.Error) {
|
||||||
if !settings.Container.Current.EnableUserVerifyEmail {
|
if !a.CurrentConfig().EnableUserVerifyEmail {
|
||||||
return nil, errs.ErrEmailValidationNotAllowed
|
return nil, errs.ErrEmailValidationNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,7 +623,7 @@ func (a *UsersApi) UserSendVerifyEmailByUnloginUserHandler(c *core.Context) (any
|
|||||||
return nil, errs.ErrEmailIsVerified
|
return nil, errs.ErrEmailIsVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
if !settings.Container.Current.EnableSMTP {
|
if !a.CurrentConfig().EnableSMTP {
|
||||||
return nil, errs.ErrSMTPServerNotEnabled
|
return nil, errs.ErrSMTPServerNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,7 +647,7 @@ func (a *UsersApi) UserSendVerifyEmailByUnloginUserHandler(c *core.Context) (any
|
|||||||
|
|
||||||
// UserSendVerifyEmailByLoginedUserHandler sends logined user verify email
|
// UserSendVerifyEmailByLoginedUserHandler sends logined user verify email
|
||||||
func (a *UsersApi) UserSendVerifyEmailByLoginedUserHandler(c *core.Context) (any, *errs.Error) {
|
func (a *UsersApi) UserSendVerifyEmailByLoginedUserHandler(c *core.Context) (any, *errs.Error) {
|
||||||
if !settings.Container.Current.EnableUserVerifyEmail {
|
if !a.CurrentConfig().EnableUserVerifyEmail {
|
||||||
return nil, errs.ErrEmailValidationNotAllowed
|
return nil, errs.ErrEmailValidationNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +667,7 @@ func (a *UsersApi) UserSendVerifyEmailByLoginedUserHandler(c *core.Context) (any
|
|||||||
return nil, errs.ErrEmailIsVerified
|
return nil, errs.ErrEmailIsVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
if !settings.Container.Current.EnableSMTP {
|
if !a.CurrentConfig().EnableSMTP {
|
||||||
return nil, errs.ErrSMTPServerNotEnabled
|
return nil, errs.ErrSMTPServerNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,46 +707,19 @@ func (a *UsersApi) UserGetAvatarHandler(c *core.Context) ([]byte, string, *errs.
|
|||||||
return nil, "", errs.ErrUserIdInvalid
|
return nil, "", errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := a.users.GetUserById(c, uid)
|
avatarData, err := a.users.GetUserAvatar(c, uid, fileExtension)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errs.IsCustomError(err) {
|
if !errs.IsCustomError(err) {
|
||||||
log.ErrorfWithRequestId(c, "[users.UserGetAvatarHandler] failed to get user, because %s", err.Error())
|
log.ErrorfWithRequestId(c, "[users.UserGetAvatarHandler] failed to get user avatar, because %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, "", errs.ErrUserNotFound
|
return nil, "", errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
|
||||||
|
|
||||||
if user.CustomAvatarType == "" {
|
|
||||||
log.WarnfWithRequestId(c, "[users.UserGetAvatarHandler] user does not have avatar for user \"uid:%d\"", user.Uid)
|
|
||||||
return nil, "", errs.ErrUserAvatarNoExists
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.CustomAvatarType != fileExtension {
|
|
||||||
log.WarnfWithRequestId(c, "[users.UserGetAvatarHandler] user avatar extension is invalid \"%s\" for user \"uid:%d\"", fileExtension, user.Uid)
|
|
||||||
return nil, "", errs.ErrUserAvatarNoExists
|
|
||||||
}
|
|
||||||
|
|
||||||
avatarFile, err := storage.Container.ReadAvatar(user.Uid, fileExtension)
|
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
log.WarnfWithRequestId(c, "[users.UserGetAvatarHandler] user avatar file not exist for user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, "", errs.ErrUserAvatarNoExists
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserGetAvatarHandler] failed to get user avatar object for user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, "", errs.ErrOperationFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
defer avatarFile.Close()
|
|
||||||
|
|
||||||
avatarData, err := io.ReadAll(avatarFile)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.ErrorfWithRequestId(c, "[users.UserGetAvatarHandler] failed to read user avatar object data for user \"uid:%d\", because %s", user.Uid, err.Error())
|
|
||||||
return nil, "", errs.ErrOperationFailed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return avatarData, contentType, nil
|
return avatarData, contentType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *UsersApi) getUserProfileResponse(user *models.User) *models.UserProfileResponse {
|
||||||
|
return user.ToUserProfileResponse(a.CurrentConfig().AvatarProvider, a.CurrentConfig().RootUrl)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import "github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
|
||||||
|
// CliUsingConfig represents an cli that need to use config
|
||||||
|
type CliUsingConfig struct {
|
||||||
|
container *settings.ConfigContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentConfig returns the current config
|
||||||
|
func (l *CliUsingConfig) CurrentConfig() *settings.Config {
|
||||||
|
return l.container.Current
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ const pageCountForDataExport = 1000
|
|||||||
|
|
||||||
// UserDataCli represents user data cli
|
// UserDataCli represents user data cli
|
||||||
type UserDataCli struct {
|
type UserDataCli struct {
|
||||||
|
CliUsingConfig
|
||||||
ezBookKeepingCsvExporter *converters.EzBookKeepingCSVFileExporter
|
ezBookKeepingCsvExporter *converters.EzBookKeepingCSVFileExporter
|
||||||
ezBookKeepingTsvExporter *converters.EzBookKeepingTSVFileExporter
|
ezBookKeepingTsvExporter *converters.EzBookKeepingTSVFileExporter
|
||||||
accounts *services.AccountService
|
accounts *services.AccountService
|
||||||
@@ -34,6 +35,9 @@ type UserDataCli struct {
|
|||||||
// Initialize an user data cli singleton instance
|
// Initialize an user data cli singleton instance
|
||||||
var (
|
var (
|
||||||
UserData = &UserDataCli{
|
UserData = &UserDataCli{
|
||||||
|
CliUsingConfig: CliUsingConfig{
|
||||||
|
container: settings.Container,
|
||||||
|
},
|
||||||
ezBookKeepingCsvExporter: &converters.EzBookKeepingCSVFileExporter{},
|
ezBookKeepingCsvExporter: &converters.EzBookKeepingCSVFileExporter{},
|
||||||
ezBookKeepingTsvExporter: &converters.EzBookKeepingTSVFileExporter{},
|
ezBookKeepingTsvExporter: &converters.EzBookKeepingTSVFileExporter{},
|
||||||
accounts: services.Accounts,
|
accounts: services.Accounts,
|
||||||
@@ -180,7 +184,7 @@ func (l *UserDataCli) SendPasswordResetMail(c *cli.Context, username string) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Container.Current.ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
if l.CurrentConfig().ForgetPasswordRequireVerifyEmail && !user.EmailVerified {
|
||||||
log.BootWarnf("[user_data.SendPasswordResetMail] user \"uid:%d\" has not verified email", user.Uid)
|
log.BootWarnf("[user_data.SendPasswordResetMail] user \"uid:%d\" has not verified email", user.Uid)
|
||||||
return errs.ErrEmailIsNotVerified
|
return errs.ErrEmailIsNotVerified
|
||||||
}
|
}
|
||||||
@@ -238,7 +242,7 @@ func (l *UserDataCli) DisableUser(c *cli.Context, username string) error {
|
|||||||
|
|
||||||
// ResendVerifyEmail resends an email with account activation link
|
// ResendVerifyEmail resends an email with account activation link
|
||||||
func (l *UserDataCli) ResendVerifyEmail(c *cli.Context, username string) error {
|
func (l *UserDataCli) ResendVerifyEmail(c *cli.Context, username string) error {
|
||||||
if !settings.Container.Current.EnableUserVerifyEmail {
|
if !l.CurrentConfig().EnableUserVerifyEmail {
|
||||||
return errs.ErrEmailValidationNotAllowed
|
return errs.ErrEmailValidationNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
// UserAvatarProviderType represents type of the user avatar provider
|
||||||
|
type UserAvatarProviderType string
|
||||||
|
|
||||||
|
// User avatar provider types
|
||||||
|
const (
|
||||||
|
USER_AVATAR_PROVIDER_INTERNAL UserAvatarProviderType = "internal"
|
||||||
|
USER_AVATAR_PROVIDER_GRAVATAR UserAvatarProviderType = "gravatar"
|
||||||
|
)
|
||||||
@@ -34,4 +34,6 @@ var (
|
|||||||
ErrNoUserAvatar = NewNormalError(NormalSubcategoryUser, 25, http.StatusBadRequest, "no user avatar")
|
ErrNoUserAvatar = NewNormalError(NormalSubcategoryUser, 25, http.StatusBadRequest, "no user avatar")
|
||||||
ErrUserAvatarIsEmpty = NewNormalError(NormalSubcategoryUser, 26, http.StatusBadRequest, "user avatar is empty")
|
ErrUserAvatarIsEmpty = NewNormalError(NormalSubcategoryUser, 26, http.StatusBadRequest, "user avatar is empty")
|
||||||
ErrUserAvatarNoExists = NewNormalError(NormalSubcategoryUser, 27, http.StatusNotFound, "user avatar not exists")
|
ErrUserAvatarNoExists = NewNormalError(NormalSubcategoryUser, 27, http.StatusNotFound, "user avatar not exists")
|
||||||
|
ErrUserAvatarNotSet = NewNormalError(NormalSubcategoryUser, 28, http.StatusNotFound, "user avatar not set")
|
||||||
|
ErrUserAvatarExtensionInvalid = NewNormalError(NormalSubcategoryUser, 29, http.StatusNotFound, "user avatar file extension invalid")
|
||||||
)
|
)
|
||||||
|
|||||||
+9
-16
@@ -5,7 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -253,13 +252,13 @@ func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, utcOff
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToUserBasicInfo returns a user basic view-object according to database model
|
// ToUserBasicInfo returns a user basic view-object according to database model
|
||||||
func (u *User) ToUserBasicInfo() *UserBasicInfo {
|
func (u *User) ToUserBasicInfo(avatarProvider core.UserAvatarProviderType, rootUrl string) *UserBasicInfo {
|
||||||
return &UserBasicInfo{
|
return &UserBasicInfo{
|
||||||
Username: u.Username,
|
Username: u.Username,
|
||||||
Email: u.Email,
|
Email: u.Email,
|
||||||
Nickname: u.Nickname,
|
Nickname: u.Nickname,
|
||||||
AvatarUrl: u.getAvatarUrl(),
|
AvatarUrl: u.getAvatarUrl(avatarProvider, rootUrl),
|
||||||
AvatarProvider: u.getAvatarProvider(),
|
AvatarProvider: string(avatarProvider),
|
||||||
DefaultAccountId: u.DefaultAccountId,
|
DefaultAccountId: u.DefaultAccountId,
|
||||||
TransactionEditScope: u.TransactionEditScope,
|
TransactionEditScope: u.TransactionEditScope,
|
||||||
Language: u.Language,
|
Language: u.Language,
|
||||||
@@ -280,23 +279,17 @@ func (u *User) ToUserBasicInfo() *UserBasicInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToUserProfileResponse returns a user profile view-object according to database model
|
// ToUserProfileResponse returns a user profile view-object according to database model
|
||||||
func (u *User) ToUserProfileResponse() *UserProfileResponse {
|
func (u *User) ToUserProfileResponse(avatarProvider core.UserAvatarProviderType, rootUrl string) *UserProfileResponse {
|
||||||
return &UserProfileResponse{
|
return &UserProfileResponse{
|
||||||
UserBasicInfo: u.ToUserBasicInfo(),
|
UserBasicInfo: u.ToUserBasicInfo(avatarProvider, rootUrl),
|
||||||
LastLoginAt: u.LastLoginUnixTime,
|
LastLoginAt: u.LastLoginUnixTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) getAvatarProvider() string {
|
func (u *User) getAvatarUrl(avatarProvider core.UserAvatarProviderType, rootUrl string) string {
|
||||||
return settings.Container.Current.AvatarProvider
|
if avatarProvider == core.USER_AVATAR_PROVIDER_INTERNAL {
|
||||||
}
|
return utils.GetInternalAvatarUrl(u.Uid, u.CustomAvatarType, rootUrl)
|
||||||
|
} else if avatarProvider == core.USER_AVATAR_PROVIDER_GRAVATAR {
|
||||||
func (u *User) getAvatarUrl() string {
|
|
||||||
avatarProvider := settings.Container.Current.AvatarProvider
|
|
||||||
|
|
||||||
if avatarProvider == settings.InternalAvatarProvider {
|
|
||||||
return utils.GetInternalAvatarUrl(u.Uid, u.CustomAvatarType, settings.Container.Current.RootUrl)
|
|
||||||
} else if avatarProvider == settings.GravatarProvider {
|
|
||||||
return utils.GetGravatarUrl(u.Email)
|
return utils.GetGravatarUrl(u.Email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/datastore"
|
"github.com/mayswind/ezbookkeeping/pkg/datastore"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/mail"
|
"github.com/mayswind/ezbookkeeping/pkg/mail"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/storage"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,3 +79,32 @@ func (s *ServiceUsingUuid) GenerateUuid(uuidType uuid.UuidType) int64 {
|
|||||||
func (s *ServiceUsingUuid) GenerateUuids(uuidType uuid.UuidType, count uint8) []int64 {
|
func (s *ServiceUsingUuid) GenerateUuids(uuidType uuid.UuidType, count uint8) []int64 {
|
||||||
return s.container.GenerateUuids(uuidType, count)
|
return s.container.GenerateUuids(uuidType, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServiceUsingStorage represents a service that need to use storage
|
||||||
|
type ServiceUsingStorage struct {
|
||||||
|
container *storage.StorageContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExistsAvatar returns whether the user avatar exists from the current avatar object storage
|
||||||
|
func (s *ServiceUsingStorage) ExistsAvatar(uid int64, fileExtension string) (bool, error) {
|
||||||
|
return s.container.ExistsAvatar(s.getUserAvatarPath(uid, fileExtension))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAvatar returns the user avatar from the current avatar object storage
|
||||||
|
func (s *ServiceUsingStorage) ReadAvatar(uid int64, fileExtension string) (storage.ObjectInStorage, error) {
|
||||||
|
return s.container.ReadAvatar(s.getUserAvatarPath(uid, fileExtension))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveAvatar returns whether save the user avatar into the current avatar object storage successfully
|
||||||
|
func (s *ServiceUsingStorage) SaveAvatar(uid int64, object storage.ObjectInStorage, fileExtension string) error {
|
||||||
|
return s.container.SaveAvatar(s.getUserAvatarPath(uid, fileExtension), object)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAvatar returns whether delete the user avatar from the current avatar object storage successfully
|
||||||
|
func (s *ServiceUsingStorage) DeleteAvatar(uid int64, fileExtension string) error {
|
||||||
|
return s.container.DeleteAvatar(s.getUserAvatarPath(uid, fileExtension))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceUsingStorage) getUserAvatarPath(uid int64, fileExtension string) string {
|
||||||
|
return fmt.Sprintf("%d.%s", uid, fileExtension)
|
||||||
|
}
|
||||||
|
|||||||
+103
-3
@@ -3,7 +3,10 @@ package services
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
@@ -12,9 +15,11 @@ import (
|
|||||||
"github.com/mayswind/ezbookkeeping/pkg/datastore"
|
"github.com/mayswind/ezbookkeeping/pkg/datastore"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/locales"
|
"github.com/mayswind/ezbookkeeping/pkg/locales"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/log"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/mail"
|
"github.com/mayswind/ezbookkeeping/pkg/mail"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/storage"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/templates"
|
"github.com/mayswind/ezbookkeeping/pkg/templates"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
||||||
@@ -28,6 +33,7 @@ type UserService struct {
|
|||||||
ServiceUsingConfig
|
ServiceUsingConfig
|
||||||
ServiceUsingMailer
|
ServiceUsingMailer
|
||||||
ServiceUsingUuid
|
ServiceUsingUuid
|
||||||
|
ServiceUsingStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a user service singleton instance
|
// Initialize a user service singleton instance
|
||||||
@@ -45,6 +51,9 @@ var (
|
|||||||
ServiceUsingUuid: ServiceUsingUuid{
|
ServiceUsingUuid: ServiceUsingUuid{
|
||||||
container: uuid.Container,
|
container: uuid.Container,
|
||||||
},
|
},
|
||||||
|
ServiceUsingStorage: ServiceUsingStorage{
|
||||||
|
container: storage.Container,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -126,6 +135,50 @@ func (s *UserService) GetUserByEmail(c *core.Context, email string) (*models.Use
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserAvatar returns the user avatar image data and image file extension according to user uid
|
||||||
|
func (s *UserService) GetUserAvatar(c *core.Context, uid int64, fileExtension string) ([]byte, error) {
|
||||||
|
if uid <= 0 {
|
||||||
|
return nil, errs.ErrUserIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &models.User{}
|
||||||
|
has, err := s.UserDB().NewSession(c).ID(uid).Cols("uid", "deleted", "custom_avatar_type").Where("deleted=?", false).Get(user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, errs.ErrUserNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.CustomAvatarType == "" {
|
||||||
|
return nil, errs.ErrUserAvatarNotSet
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.CustomAvatarType != fileExtension {
|
||||||
|
return nil, errs.ErrUserAvatarExtensionInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarFile, err := s.ReadAvatar(user.Uid, user.CustomAvatarType)
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, errs.ErrUserAvatarNoExists
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer avatarFile.Close()
|
||||||
|
|
||||||
|
avatarData, err := io.ReadAll(avatarFile)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatarData, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateUser saves a new user model to database
|
// CreateUser saves a new user model to database
|
||||||
func (s *UserService) CreateUser(c *core.Context, user *models.User) error {
|
func (s *UserService) CreateUser(c *core.Context, user *models.User) error {
|
||||||
exists, err := s.ExistsUsername(c, user.Username)
|
exists, err := s.ExistsUsername(c, user.Username)
|
||||||
@@ -294,16 +347,63 @@ func (s *UserService) UpdateUser(c *core.Context, user *models.User, modifyUserL
|
|||||||
return keyProfileUpdated, emailSetToUnverified, nil
|
return keyProfileUpdated, emailSetToUnverified, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserAvatar updated the custom avatar type of specified user
|
// UpdateUserAvatar updates the custom avatar type of specified user
|
||||||
func (s *UserService) UpdateUserAvatar(c *core.Context, uid int64, customAvatarType string) error {
|
func (s *UserService) UpdateUserAvatar(c *core.Context, uid int64, avatarFile multipart.File, fileExtension string, oldFileExtension string) error {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer avatarFile.Close()
|
||||||
|
|
||||||
|
err := s.SaveAvatar(uid, avatarFile, fileExtension)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
|
|
||||||
updateModel := &models.User{
|
updateModel := &models.User{
|
||||||
CustomAvatarType: customAvatarType,
|
CustomAvatarType: fileExtension,
|
||||||
|
UpdatedUnixTime: now,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.UserDB().DoTransaction(c, func(sess *xorm.Session) error {
|
||||||
|
_, err := sess.ID(uid).Cols("custom_avatar_type", "updated_unix_time").Where("deleted=?", false).Update(updateModel)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fileExtension != oldFileExtension && oldFileExtension != "" {
|
||||||
|
err = s.DeleteAvatar(uid, oldFileExtension)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WarnfWithRequestId(c, "[users.UpdateUserAvatar] failed to delete old avatar with extension \"%s\" for user \"uid:%d\", because %s", oldFileExtension, uid, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveUserAvatar removes the custom avatar type of specified user
|
||||||
|
func (s *UserService) RemoveUserAvatar(c *core.Context, uid int64, fileExtension string) error {
|
||||||
|
if uid <= 0 {
|
||||||
|
return errs.ErrUserIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.DeleteAvatar(uid, fileExtension)
|
||||||
|
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
|
||||||
|
updateModel := &models.User{
|
||||||
|
CustomAvatarType: "",
|
||||||
UpdatedUnixTime: now,
|
UpdatedUnixTime: now,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-11
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/locales"
|
"github.com/mayswind/ezbookkeeping/pkg/locales"
|
||||||
)
|
)
|
||||||
@@ -74,12 +75,6 @@ const (
|
|||||||
InMemoryDuplicateCheckerType string = "in_memory"
|
InMemoryDuplicateCheckerType string = "in_memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User avatar provider types
|
|
||||||
const (
|
|
||||||
InternalAvatarProvider string = "internal"
|
|
||||||
GravatarProvider string = "gravatar"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Map provider types
|
// Map provider types
|
||||||
const (
|
const (
|
||||||
OpenStreetMapProvider string = "openstreetmap"
|
OpenStreetMapProvider string = "openstreetmap"
|
||||||
@@ -276,7 +271,7 @@ type Config struct {
|
|||||||
EnableUserForceVerifyEmail bool
|
EnableUserForceVerifyEmail bool
|
||||||
EnableUserForgetPassword bool
|
EnableUserForgetPassword bool
|
||||||
ForgetPasswordRequireVerifyEmail bool
|
ForgetPasswordRequireVerifyEmail bool
|
||||||
AvatarProvider string
|
AvatarProvider core.UserAvatarProviderType
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
EnableDataExport bool
|
EnableDataExport bool
|
||||||
@@ -744,10 +739,10 @@ func loadUserConfiguration(config *Config, configFile *ini.File, sectionName str
|
|||||||
config.EnableUserForgetPassword = getConfigItemBoolValue(configFile, sectionName, "enable_forget_password", false)
|
config.EnableUserForgetPassword = getConfigItemBoolValue(configFile, sectionName, "enable_forget_password", false)
|
||||||
config.ForgetPasswordRequireVerifyEmail = getConfigItemBoolValue(configFile, sectionName, "forget_password_require_email_verify", false)
|
config.ForgetPasswordRequireVerifyEmail = getConfigItemBoolValue(configFile, sectionName, "forget_password_require_email_verify", false)
|
||||||
|
|
||||||
if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == InternalAvatarProvider {
|
if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == string(core.USER_AVATAR_PROVIDER_INTERNAL) {
|
||||||
config.AvatarProvider = InternalAvatarProvider
|
config.AvatarProvider = core.USER_AVATAR_PROVIDER_INTERNAL
|
||||||
} else if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == GravatarProvider {
|
} else if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == string(core.USER_AVATAR_PROVIDER_GRAVATAR) {
|
||||||
config.AvatarProvider = GravatarProvider
|
config.AvatarProvider = core.USER_AVATAR_PROVIDER_GRAVATAR
|
||||||
} else if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == "" {
|
} else if getConfigItemStringValue(configFile, sectionName, "avatar_provider") == "" {
|
||||||
config.AvatarProvider = ""
|
config.AvatarProvider = ""
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,60 +16,3 @@ var (
|
|||||||
func SetCurrentConfig(config *Config) {
|
func SetCurrentConfig(config *Config) {
|
||||||
Container.Current = config
|
Container.Current = config
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAfterRegisterNotificationContent returns the notification content displayed each time users register
|
|
||||||
func (c *ConfigContainer) GetAfterRegisterNotificationContent(userLanguage string, clientLanguage string) string {
|
|
||||||
language := userLanguage
|
|
||||||
|
|
||||||
if language == "" {
|
|
||||||
language = clientLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Current.AfterRegisterNotification.Enabled {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if multiLanguageContent, exists := c.Current.AfterRegisterNotification.MultiLanguageContent[language]; exists {
|
|
||||||
return multiLanguageContent
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Current.AfterRegisterNotification.DefaultContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAfterLoginNotificationContent returns the notification content displayed each time users log in
|
|
||||||
func (c *ConfigContainer) GetAfterLoginNotificationContent(userLanguage string, clientLanguage string) string {
|
|
||||||
language := userLanguage
|
|
||||||
|
|
||||||
if language == "" {
|
|
||||||
language = clientLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Current.AfterLoginNotification.Enabled {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if multiLanguageContent, exists := c.Current.AfterLoginNotification.MultiLanguageContent[language]; exists {
|
|
||||||
return multiLanguageContent
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Current.AfterLoginNotification.DefaultContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAfterOpenNotificationContent returns the notification content displayed each time users open the app
|
|
||||||
func (c *ConfigContainer) GetAfterOpenNotificationContent(userLanguage string, clientLanguage string) string {
|
|
||||||
language := userLanguage
|
|
||||||
|
|
||||||
if language == "" {
|
|
||||||
language = clientLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Current.AfterOpenNotification.Enabled {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if multiLanguageContent, exists := c.Current.AfterOpenNotification.MultiLanguageContent[language]; exists {
|
|
||||||
return multiLanguageContent
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.Current.AfterOpenNotification.DefaultContent
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
)
|
)
|
||||||
@@ -36,26 +34,22 @@ func InitializeStorageContainer(config *settings.Config) error {
|
|||||||
return errs.ErrInvalidStorageType
|
return errs.ErrInvalidStorageType
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistsAvatar returns whether the user avatar exists from the current object storage
|
// ExistsAvatar returns whether the avatar file exists from the current avatar object storage
|
||||||
func (s *StorageContainer) ExistsAvatar(uid int64, fileExtension string) (bool, error) {
|
func (s *StorageContainer) ExistsAvatar(path string) (bool, error) {
|
||||||
return s.AvatarCurrentStorage.Exists(s.getUserAvatarPath(uid, fileExtension))
|
return s.AvatarCurrentStorage.Exists(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAvatar returns the user avatar from the current object storage
|
// ReadAvatar returns the avatar file from the current avatar object storage
|
||||||
func (s *StorageContainer) ReadAvatar(uid int64, fileExtension string) (ObjectInStorage, error) {
|
func (s *StorageContainer) ReadAvatar(path string) (ObjectInStorage, error) {
|
||||||
return s.AvatarCurrentStorage.Read(s.getUserAvatarPath(uid, fileExtension))
|
return s.AvatarCurrentStorage.Read(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAvatar returns whether save the user avatar into the current object storage successfully
|
// SaveAvatar returns whether save the avatar file into the current avatar object storage successfully
|
||||||
func (s *StorageContainer) SaveAvatar(uid int64, object ObjectInStorage, fileExtension string) error {
|
func (s *StorageContainer) SaveAvatar(path string, object ObjectInStorage) error {
|
||||||
return s.AvatarCurrentStorage.Save(s.getUserAvatarPath(uid, fileExtension), object)
|
return s.AvatarCurrentStorage.Save(path, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAvatar returns whether delete the user avatar from the current object storage successfully
|
// DeleteAvatar returns whether delete the avatar file from the current avatar object storage successfully
|
||||||
func (s *StorageContainer) DeleteAvatar(uid int64, fileExtension string) error {
|
func (s *StorageContainer) DeleteAvatar(path string) error {
|
||||||
return s.AvatarCurrentStorage.Delete(s.getUserAvatarPath(uid, fileExtension))
|
return s.AvatarCurrentStorage.Delete(path)
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StorageContainer) getUserAvatarPath(uid int64, fileExtension string) string {
|
|
||||||
return fmt.Sprintf("%d.%s", uid, fileExtension)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -967,6 +967,8 @@
|
|||||||
"no user avatar": "There is no user avatar file",
|
"no user avatar": "There is no user avatar file",
|
||||||
"user avatar is empty": "User avatar file is empty",
|
"user avatar is empty": "User avatar file is empty",
|
||||||
"user avatar not exists": "User avatar does not exist",
|
"user avatar not exists": "User avatar does not exist",
|
||||||
|
"user avatar not set": "User avatar is not set",
|
||||||
|
"user avatar file extension invalid": "User avatar file extension is invalid",
|
||||||
"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",
|
||||||
|
|||||||
@@ -967,6 +967,8 @@
|
|||||||
"no user avatar": "没有用户头像文件",
|
"no user avatar": "没有用户头像文件",
|
||||||
"user avatar is empty": "用户头像文件为空",
|
"user avatar is empty": "用户头像文件为空",
|
||||||
"user avatar not exists": "用户头像不存在",
|
"user avatar not exists": "用户头像不存在",
|
||||||
|
"user avatar not set": "用户没有设置头像",
|
||||||
|
"user avatar file extension invalid": "用户头像文件扩展名无效",
|
||||||
"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