mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 17:54:30 +08:00
display notification every time users open the app or login
This commit is contained in:
@@ -187,6 +187,21 @@ avatar_provider = internal
|
|||||||
# Set to true to allow users to export their data
|
# Set to true to allow users to export their data
|
||||||
enable_export = true
|
enable_export = true
|
||||||
|
|
||||||
|
[notification]
|
||||||
|
# Set to true to display custom notification in home page every time users login
|
||||||
|
enable_notification_after_login = false
|
||||||
|
|
||||||
|
# The notification content displayed each time users log in, it supports multi-language configuration
|
||||||
|
# Add an underscore and a language tag after the setting key to configure the notification content in that language, the same below
|
||||||
|
# For example, after_login_notification_content_zh_hans means the notification content in Simplified Chinese
|
||||||
|
after_login_notification_content =
|
||||||
|
|
||||||
|
# Set to true to display custom notification in home page every time users open the app
|
||||||
|
enable_notification_after_open = false
|
||||||
|
|
||||||
|
# The notification content displayed each time users open the app, it supports multi-language configuration
|
||||||
|
after_open_notification_content =
|
||||||
|
|
||||||
[map]
|
[map]
|
||||||
# Map provider, supports the following types:
|
# Map provider, supports the following types:
|
||||||
# "openstreetmap": https://www.openstreetmap.org
|
# "openstreetmap": https://www.openstreetmap.org
|
||||||
|
|||||||
@@ -242,8 +242,9 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
|
|||||||
|
|
||||||
func (a *AuthorizationsApi) getAuthResponse(token string, need2FA bool, user *models.User) *models.AuthResponse {
|
func (a *AuthorizationsApi) getAuthResponse(token string, need2FA bool, user *models.User) *models.AuthResponse {
|
||||||
return &models.AuthResponse{
|
return &models.AuthResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
Need2FA: need2FA,
|
Need2FA: need2FA,
|
||||||
User: user.ToUserBasicInfo(),
|
User: user.ToUserBasicInfo(),
|
||||||
|
NotificationContent: settings.Container.GetAfterLoginNotificationContent(user.Language),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -204,7 +204,8 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refreshResp := &models.TokenRefreshResponse{
|
refreshResp := &models.TokenRefreshResponse{
|
||||||
User: user.ToUserBasicInfo(),
|
User: user.ToUserBasicInfo(),
|
||||||
|
NotificationContent: settings.Container.GetAfterOpenNotificationContent(user.Language),
|
||||||
}
|
}
|
||||||
|
|
||||||
return refreshResp, nil
|
return refreshResp, nil
|
||||||
@@ -230,9 +231,10 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
log.InfofWithRequestId(c, "[token.TokenRefreshHandler] user \"uid:%d\" token refreshed, new token will be expired at %d", user.Uid, claims.ExpiresAt)
|
log.InfofWithRequestId(c, "[token.TokenRefreshHandler] user \"uid:%d\" token refreshed, new token will be expired at %d", user.Uid, claims.ExpiresAt)
|
||||||
|
|
||||||
refreshResp := &models.TokenRefreshResponse{
|
refreshResp := &models.TokenRefreshResponse{
|
||||||
NewToken: token,
|
NewToken: token,
|
||||||
OldTokenId: a.tokens.GenerateTokenId(oldTokenRecord),
|
OldTokenId: a.tokens.GenerateTokenId(oldTokenRecord),
|
||||||
User: user.ToUserBasicInfo(),
|
User: user.ToUserBasicInfo(),
|
||||||
|
NotificationContent: settings.Container.GetAfterOpenNotificationContent(user.Language),
|
||||||
}
|
}
|
||||||
|
|
||||||
return refreshResp, nil
|
return refreshResp, nil
|
||||||
|
|||||||
+5
-2
@@ -91,8 +91,9 @@ 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: user.ToUserBasicInfo(),
|
||||||
|
NotificationContent: settings.Container.GetAfterLoginNotificationContent(user.Language),
|
||||||
},
|
},
|
||||||
NeedVerifyEmail: settings.Container.Current.EnableUserVerifyEmail && settings.Container.Current.EnableUserForceVerifyEmail,
|
NeedVerifyEmail: settings.Container.Current.EnableUserVerifyEmail && settings.Container.Current.EnableUserForceVerifyEmail,
|
||||||
PresetCategoriesSaved: presetCategoriesSaved,
|
PresetCategoriesSaved: presetCategoriesSaved,
|
||||||
@@ -187,6 +188,8 @@ func (a *UsersApi) UserEmailVerifyHandler(c *core.Context) (any, *errs.Error) {
|
|||||||
|
|
||||||
resp.NewToken = token
|
resp.NewToken = token
|
||||||
resp.User = user.ToUserBasicInfo()
|
resp.User = user.ToUserBasicInfo()
|
||||||
|
resp.NotificationContent = settings.Container.GetAfterLoginNotificationContent(user.Language)
|
||||||
|
|
||||||
c.SetTextualToken(token)
|
c.SetTextualToken(token)
|
||||||
c.SetTokenClaims(claims)
|
c.SetTokenClaims(claims)
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ package models
|
|||||||
|
|
||||||
// AuthResponse returns a view-object of user authorization
|
// AuthResponse returns a view-object of user authorization
|
||||||
type AuthResponse struct {
|
type AuthResponse struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Need2FA bool `json:"need2FA"`
|
Need2FA bool `json:"need2FA"`
|
||||||
User *UserBasicInfo `json:"user"`
|
User *UserBasicInfo `json:"user"`
|
||||||
|
NotificationContent string `json:"notificationContent,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterResponse returns a view-object of user register response
|
// RegisterResponse returns a view-object of user register response
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ type TokenRevokeRequest struct {
|
|||||||
|
|
||||||
// TokenRefreshResponse represents all parameters of token refreshing request
|
// TokenRefreshResponse represents all parameters of token refreshing request
|
||||||
type TokenRefreshResponse struct {
|
type TokenRefreshResponse struct {
|
||||||
NewToken string `json:"newToken,omitempty"`
|
NewToken string `json:"newToken,omitempty"`
|
||||||
OldTokenId string `json:"oldTokenId,omitempty"`
|
OldTokenId string `json:"oldTokenId,omitempty"`
|
||||||
User *UserBasicInfo `json:"user"`
|
User *UserBasicInfo `json:"user"`
|
||||||
|
NotificationContent string `json:"notificationContent,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenInfoResponse represents a view-object of token
|
// TokenInfoResponse represents a view-object of token
|
||||||
|
|||||||
+3
-2
@@ -164,8 +164,9 @@ type UserVerifyEmailRequest struct {
|
|||||||
|
|
||||||
// UserVerifyEmailResponse represents all response parameters after user have verified email
|
// UserVerifyEmailResponse represents all response parameters after user have verified email
|
||||||
type UserVerifyEmailResponse struct {
|
type UserVerifyEmailResponse struct {
|
||||||
NewToken string `json:"newToken,omitempty"`
|
NewToken string `json:"newToken,omitempty"`
|
||||||
User *UserBasicInfo `json:"user"`
|
User *UserBasicInfo `json:"user"`
|
||||||
|
NotificationContent string `json:"notificationContent,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserResendVerifyEmailRequest represents all parameters of user resend verify email request
|
// UserResendVerifyEmailRequest represents all parameters of user resend verify email request
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/locales"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -178,6 +179,13 @@ type MinIOConfig struct {
|
|||||||
RootPath string
|
RootPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotificationConfig represents a notification setting config
|
||||||
|
type NotificationConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
DefaultContent string
|
||||||
|
MultiLanguageContent map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
// Config represents the global setting config
|
// Config represents the global setting config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Global
|
// Global
|
||||||
@@ -263,6 +271,10 @@ type Config struct {
|
|||||||
// Data
|
// Data
|
||||||
EnableDataExport bool
|
EnableDataExport bool
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
AfterLoginNotification NotificationConfig
|
||||||
|
AfterOpenNotification NotificationConfig
|
||||||
|
|
||||||
// Map
|
// Map
|
||||||
MapProvider string
|
MapProvider string
|
||||||
EnableMapDataFetchProxy bool
|
EnableMapDataFetchProxy bool
|
||||||
@@ -371,6 +383,12 @@ func LoadConfiguration(configFilePath string) (*Config, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = loadNotificationConfiguration(config, cfgFile, "notification")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
err = loadMapConfiguration(config, cfgFile, "map")
|
err = loadMapConfiguration(config, cfgFile, "map")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -700,6 +718,13 @@ func loadDataConfiguration(config *Config, configFile *ini.File, sectionName str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadNotificationConfiguration(config *Config, configFile *ini.File, sectionName string) error {
|
||||||
|
config.AfterLoginNotification = getNotificationConfiguration(configFile, sectionName, "enable_notification_after_login", "after_login_notification_content")
|
||||||
|
config.AfterOpenNotification = getNotificationConfiguration(configFile, sectionName, "enable_notification_after_open", "after_open_notification_content")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func loadMapConfiguration(config *Config, configFile *ini.File, sectionName string) error {
|
func loadMapConfiguration(config *Config, configFile *ini.File, sectionName string) error {
|
||||||
mapProvider := getConfigItemStringValue(configFile, sectionName, "map_provider")
|
mapProvider := getConfigItemStringValue(configFile, sectionName, "map_provider")
|
||||||
|
|
||||||
@@ -820,6 +845,27 @@ func getFinalPath(workingPath, p string) (string, error) {
|
|||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNotificationConfiguration(configFile *ini.File, sectionName string, enableKey string, contentKey string) NotificationConfig {
|
||||||
|
config := NotificationConfig{
|
||||||
|
Enabled: getConfigItemBoolValue(configFile, sectionName, enableKey, false),
|
||||||
|
DefaultContent: getConfigItemStringValue(configFile, sectionName, contentKey, ""),
|
||||||
|
MultiLanguageContent: make(map[string]string),
|
||||||
|
}
|
||||||
|
|
||||||
|
for languageTag := range locales.AllLanguages {
|
||||||
|
multiLanguageContentKey := strings.ToLower(languageTag)
|
||||||
|
multiLanguageContentKey = strings.Replace(multiLanguageContentKey, "-", "_", -1)
|
||||||
|
multiLanguageContentKey = contentKey + "_" + multiLanguageContentKey
|
||||||
|
content := getConfigItemStringValue(configFile, sectionName, multiLanguageContentKey, "")
|
||||||
|
|
||||||
|
if content != "" {
|
||||||
|
config.MultiLanguageContent[languageTag] = content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
func getConfigItemIsSet(configFile *ini.File, sectionName string, itemName string) bool {
|
func getConfigItemIsSet(configFile *ini.File, sectionName string, itemName string) bool {
|
||||||
environmentKey := getEnvironmentKey(sectionName, itemName)
|
environmentKey := getEnvironmentKey(sectionName, itemName)
|
||||||
environmentValue := os.Getenv(environmentKey)
|
environmentValue := os.Getenv(environmentKey)
|
||||||
|
|||||||
@@ -16,3 +16,29 @@ var (
|
|||||||
func SetCurrentConfig(config *Config) {
|
func SetCurrentConfig(config *Config) {
|
||||||
Container.Current = config
|
Container.Current = config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAfterLoginNotificationContent returns the notification content displayed each time users log in
|
||||||
|
func (c *ConfigContainer) GetAfterLoginNotificationContent(language string) string {
|
||||||
|
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(language string) string {
|
||||||
|
if !c.Current.AfterOpenNotification.Enabled {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if multiLanguageContent, exists := c.Current.AfterOpenNotification.MultiLanguageContent[language]; exists {
|
||||||
|
return multiLanguageContent
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Current.AfterOpenNotification.DefaultContent
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user