move query parameter utc_offset to header

This commit is contained in:
MaysWind
2021-03-13 21:02:02 +08:00
parent 53340fe9fb
commit bfb56fad48
8 changed files with 59 additions and 20 deletions
+32 -4
View File
@@ -41,6 +41,13 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
} }
utcOffset, err := c.GetClientTimezoneOffset()
if err != nil {
log.WarnfWithRequestId(c, "[transactions.TransactionListHandler] cannot get client timezone offset, because %s", err.Error())
return nil, errs.ErrClientTimezoneOffsetInvalid
}
uid := c.GetCurrentUid() uid := c.GetCurrentUid()
user, err := a.users.GetUserById(uid) user, err := a.users.GetUserById(uid)
@@ -131,7 +138,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId) transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
} }
transactionEditable := transaction.IsEditable(user, transactionListReq.UtcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId]) transactionEditable := transaction.IsEditable(user, utcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId] transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResps.Items[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable) transactionResps.Items[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
} }
@@ -155,6 +162,13 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
} }
utcOffset, err := c.GetClientTimezoneOffset()
if err != nil {
log.WarnfWithRequestId(c, "[transactions.TransactionMonthListHandler] cannot get client timezone offset, because %s", err.Error())
return nil, errs.ErrClientTimezoneOffsetInvalid
}
uid := c.GetCurrentUid() uid := c.GetCurrentUid()
user, err := a.users.GetUserById(uid) user, err := a.users.GetUserById(uid)
@@ -235,7 +249,7 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId) transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
} }
transactionEditable := transaction.IsEditable(user, transactionListReq.UtcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId]) transactionEditable := transaction.IsEditable(user, utcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId] transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResps[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable) transactionResps[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
} }
@@ -253,6 +267,13 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
} }
utcOffset, err := c.GetClientTimezoneOffset()
if err != nil {
log.WarnfWithRequestId(c, "[transactions.TransactionGetHandler] cannot get client timezone offset, because %s", err.Error())
return nil, errs.ErrClientTimezoneOffsetInvalid
}
uid := c.GetCurrentUid() uid := c.GetCurrentUid()
user, err := a.users.GetUserById(uid) user, err := a.users.GetUserById(uid)
@@ -304,7 +325,7 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
return nil, errs.ErrOperationFailed return nil, errs.ErrOperationFailed
} }
transactionEditable := transaction.IsEditable(user, transactionGetReq.UtcOffset, accountMap[transaction.AccountId], accountMap[transaction.RelatedAccountId]) transactionEditable := transaction.IsEditable(user, utcOffset, accountMap[transaction.AccountId], accountMap[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId] transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResp := transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable) transactionResp := transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
@@ -497,6 +518,13 @@ func (a *TransactionsApi) TransactionDeleteHandler(c *core.Context) (interface{}
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
} }
utcOffset, err := c.GetClientTimezoneOffset()
if err != nil {
log.WarnfWithRequestId(c, "[transactions.TransactionDeleteHandler] cannot get client timezone offset, because %s", err.Error())
return nil, errs.ErrClientTimezoneOffsetInvalid
}
uid := c.GetCurrentUid() uid := c.GetCurrentUid()
user, err := a.users.GetUserById(uid) user, err := a.users.GetUserById(uid)
@@ -520,7 +548,7 @@ func (a *TransactionsApi) TransactionDeleteHandler(c *core.Context) (interface{}
return nil, errs.ErrTransactionTypeInvalid return nil, errs.ErrTransactionTypeInvalid
} }
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, transactionDeleteReq.UtcOffset) transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, utcOffset)
if !transactionEditable { if !transactionEditable {
return nil, errs.ErrCannotDeleteTransactionWithThisTransactionTime return nil, errs.ErrCannotDeleteTransactionWithThisTransactionTime
+14
View File
@@ -12,6 +12,8 @@ const requestIdFieldKey = "REQUEST_ID"
const tokenClaimsFieldKey = "TOKEN_CLAIMS" const tokenClaimsFieldKey = "TOKEN_CLAIMS"
const responseErrorFieldKey = "RESPONSE_ERROR" const responseErrorFieldKey = "RESPONSE_ERROR"
const clientTimezoneOffsetHeaderName = "X-Timezone-Offset"
// Context represents the request and response context // Context represents the request and response context
type Context struct { type Context struct {
*gin.Context *gin.Context
@@ -67,6 +69,18 @@ func (c *Context) GetCurrentUid() int64 {
return uid return uid
} }
// GetClientTimezoneOffset returns the client timezone offset
func (c *Context) GetClientTimezoneOffset() (int16, error) {
value := c.GetHeader(clientTimezoneOffsetHeaderName)
offset, err := strconv.Atoi(value)
if err != nil {
return 0, err
}
return int16(offset), nil
}
// SetResponseError sets the response error // SetResponseError sets the response error
func (c *Context) SetResponseError(error *errs.Error) { func (c *Context) SetResponseError(error *errs.Error) {
c.Set(responseErrorFieldKey, error) c.Set(responseErrorFieldKey, error)
+1
View File
@@ -15,6 +15,7 @@ var (
ErrFailedToRequestRemoteApi = NewNormalError(NormalSubcategoryGlobal, 5, http.StatusBadRequest, "failed to request third party api") ErrFailedToRequestRemoteApi = NewNormalError(NormalSubcategoryGlobal, 5, http.StatusBadRequest, "failed to request third party api")
ErrPageIndexInvalid = NewNormalError(NormalSubcategoryGlobal, 6, http.StatusBadRequest, "page index is invalid") ErrPageIndexInvalid = NewNormalError(NormalSubcategoryGlobal, 6, http.StatusBadRequest, "page index is invalid")
ErrPageCountInvalid = NewNormalError(NormalSubcategoryGlobal, 7, http.StatusBadRequest, "page count is invalid") ErrPageCountInvalid = NewNormalError(NormalSubcategoryGlobal, 7, http.StatusBadRequest, "page count is invalid")
ErrClientTimezoneOffsetInvalid = NewNormalError(NormalSubcategoryGlobal, 8, http.StatusBadRequest, "client timezone offset is invalid")
) )
// GetParameterInvalidMessage returns specific error message for invalid parameter error // GetParameterInvalidMessage returns specific error message for invalid parameter error
+3 -7
View File
@@ -56,13 +56,13 @@ type TransactionCreateRequest struct {
Type TransactionType `json:"type" binding:"required"` Type TransactionType `json:"type" binding:"required"`
CategoryId int64 `json:"categoryId,string"` CategoryId int64 `json:"categoryId,string"`
Time int64 `json:"time" binding:"required,min=1"` Time int64 `json:"time" binding:"required,min=1"`
UtcOffset int16 `json:"utcOffset" binding:"min=-720,max=840"`
SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"` SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"` DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"`
SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"` SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"`
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"` DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"` TagIds []string `json:"tagIds"`
Comment string `json:"comment" binding:"max=255"` Comment string `json:"comment" binding:"max=255"`
UtcOffset int `json:"utcOffset" binding:"required,min=-720,max=840"`
} }
// TransactionModifyRequest represents all parameters of transaction modification request // TransactionModifyRequest represents all parameters of transaction modification request
@@ -70,13 +70,13 @@ type TransactionModifyRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"` Id int64 `json:"id,string" binding:"required,min=1"`
CategoryId int64 `json:"categoryId,string"` CategoryId int64 `json:"categoryId,string"`
Time int64 `json:"time" binding:"required,min=1"` Time int64 `json:"time" binding:"required,min=1"`
UtcOffset int16 `json:"utcOffset" binding:"min=-720,max=840"`
SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"` SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"` DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"`
SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"` SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"`
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"` DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"` TagIds []string `json:"tagIds"`
Comment string `json:"comment" binding:"max=255"` Comment string `json:"comment" binding:"max=255"`
UtcOffset int `json:"utcOffset" binding:"required,min=-720,max=840"`
} }
// TransactionListByMaxTimeRequest represents all parameters of transaction listing by max time request // TransactionListByMaxTimeRequest represents all parameters of transaction listing by max time request
@@ -88,7 +88,6 @@ type TransactionListByMaxTimeRequest struct {
MaxTime int64 `form:"max_time" binding:"min=0"` MaxTime int64 `form:"max_time" binding:"min=0"`
MinTime int64 `form:"min_time" binding:"min=0"` MinTime int64 `form:"min_time" binding:"min=0"`
Count int `form:"count" binding:"required,min=1,max=50"` Count int `form:"count" binding:"required,min=1,max=50"`
UtcOffset int `form:"utc_offset" binding:"required,min=-720,max=840"`
} }
// TransactionListInMonthByPageRequest represents all parameters of transaction listing by month request // TransactionListInMonthByPageRequest represents all parameters of transaction listing by month request
@@ -101,19 +100,16 @@ type TransactionListInMonthByPageRequest struct {
Keyword string `form:"keyword"` Keyword string `form:"keyword"`
Page int `form:"page" binding:"required,min=1"` Page int `form:"page" binding:"required,min=1"`
Count int `form:"count" binding:"required,min=1,max=50"` Count int `form:"count" binding:"required,min=1,max=50"`
UtcOffset int `form:"utc_offset" binding:"required,min=-720,max=840"`
} }
// TransactionGetRequest represents all parameters of transaction getting request // TransactionGetRequest represents all parameters of transaction getting request
type TransactionGetRequest struct { type TransactionGetRequest struct {
Id int64 `form:"id,string" binding:"required,min=1"` Id int64 `form:"id,string" binding:"required,min=1"`
UtcOffset int `form:"utc_offset" binding:"required,min=-720,max=840"`
} }
// TransactionDeleteRequest represents all parameters of transaction deleting request // TransactionDeleteRequest represents all parameters of transaction deleting request
type TransactionDeleteRequest struct { type TransactionDeleteRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"` Id int64 `json:"id,string" binding:"required,min=1"`
UtcOffset int `form:"utc_offset" binding:"required,min=-720,max=840"`
} }
// TransactionInfoResponse represents a view-object of transaction // TransactionInfoResponse represents a view-object of transaction
@@ -139,7 +135,7 @@ type TransactionInfoPageWrapperResponse struct {
} }
// IsEditable returns whether this transaction can be edited // IsEditable returns whether this transaction can be edited
func (t *Transaction) IsEditable(currentUser *User, utcOffset int, account *Account, relatedAccount *Account) bool { func (t *Transaction) IsEditable(currentUser *User, utcOffset int16, account *Account, relatedAccount *Account) bool {
if currentUser == nil || !currentUser.CanEditTransactionByTransactionTime(t.TransactionTime, utcOffset) { if currentUser == nil || !currentUser.CanEditTransactionByTransactionTime(t.TransactionTime, utcOffset) {
return false return false
} }
+2 -2
View File
@@ -124,7 +124,7 @@ type UserProfileResponse struct {
} }
// CanEditTransactionByTransactionTime returns whether this user can edit transaction with specified transaction time // CanEditTransactionByTransactionTime returns whether this user can edit transaction with specified transaction time
func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, utcOffset int) bool { func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, utcOffset int16) bool {
if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_NONE { if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_NONE {
return false return false
} else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_ALL { } else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_ALL {
@@ -141,7 +141,7 @@ func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, utcOff
_, serverUtcOffset := now.Zone() _, serverUtcOffset := now.Zone()
serverTodayFirstUnixTime := now.Unix() - int64(now.Hour()*60*60+now.Minute()*60+now.Second()) serverTodayFirstUnixTime := now.Unix() - int64(now.Hour()*60*60+now.Minute()*60+now.Second())
clientTodayFirstUnixTime := serverTodayFirstUnixTime + int64(utcOffset*60-serverUtcOffset) clientTodayFirstUnixTime := serverTodayFirstUnixTime + int64(utcOffset)*60 - int64(serverUtcOffset)
if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER { if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER {
return transactionUnixTime >= clientTodayFirstUnixTime return transactionUnixTime >= clientTodayFirstUnixTime
+5 -7
View File
@@ -16,6 +16,8 @@ axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`;
} }
config.headers['X-Timezone-Offset'] = utils.getTimezoneOffsetMinutes();
if (needBlockRequest && !config.ignoreBlocked) { if (needBlockRequest && !config.ignoreBlocked) {
return new Promise(resolve => { return new Promise(resolve => {
blockedRequests.push(newToken => { blockedRequests.push(newToken => {
@@ -251,12 +253,10 @@ export default {
}); });
}, },
getTransactions: ({ maxTime, minTime, type, categoryId, accountId, keyword }) => { getTransactions: ({ maxTime, minTime, type, categoryId, accountId, keyword }) => {
const utcOffset = utils.getTimezoneOffsetMinutes(); return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&count=50`);
return axios.get(`v1/transactions/list.json?max_time=${maxTime}&min_time=${minTime}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&count=50&utc_offset=${utcOffset}`);
}, },
getTransaction: ({ id }) => { getTransaction: ({ id }) => {
const utcOffset = utils.getTimezoneOffsetMinutes(); return axios.get(`v1/transactions/get.json?id=${id}`);
return axios.get(`v1/transactions/get.json?id=${id}&utc_offset=${utcOffset}`);
}, },
addTransaction: ({ type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment, utcOffset }) => { addTransaction: ({ type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment, utcOffset }) => {
return axios.post('v1/transactions/add.json', { return axios.post('v1/transactions/add.json', {
@@ -288,10 +288,8 @@ export default {
}); });
}, },
deleteTransaction: ({ id }) => { deleteTransaction: ({ id }) => {
const utcOffset = utils.getTimezoneOffsetMinutes();
return axios.post('v1/transactions/delete.json', { return axios.post('v1/transactions/delete.json', {
id, id
utcOffset
}); });
}, },
getAllTransactionCategories: () => { getAllTransactionCategories: () => {
+1
View File
@@ -491,6 +491,7 @@ export default {
'operation failed': 'Operation failed', 'operation failed': 'Operation failed',
'nothing will be updated': 'Nothing will be updated', 'nothing will be updated': 'Nothing will be updated',
'failed to request third party api': 'Failed to request third party api', 'failed to request third party api': 'Failed to request third party api',
'client timezone offset is invalid': 'Client timezone offset is invalid',
'user id is invalid': 'User ID is invalid', 'user id is invalid': 'User ID is invalid',
'username is empty': 'Username is empty', 'username is empty': 'Username is empty',
'email is empty': 'Email is empty', 'email is empty': 'Email is empty',
+1
View File
@@ -491,6 +491,7 @@ export default {
'operation failed': '操作失败', 'operation failed': '操作失败',
'nothing will be updated': '没有内容更新', 'nothing will be updated': '没有内容更新',
'failed to request third party api': '请求第三方接口失败', 'failed to request third party api': '请求第三方接口失败',
'client timezone offset is invalid': '客户端时区时间差异无效',
'user id is invalid': '用户ID无效', 'user id is invalid': '用户ID无效',
'username is empty': '用户名为空', 'username is empty': '用户名为空',
'email is empty': '电子邮箱为空', 'email is empty': '电子邮箱为空',