diff --git a/pkg/api/transactions.go b/pkg/api/transactions.go
index ff726366..c19c89b9 100644
--- a/pkg/api/transactions.go
+++ b/pkg/api/transactions.go
@@ -17,6 +17,7 @@ type TransactionsApi struct {
transactionCategories *services.TransactionCategoryService
transactionTags *services.TransactionTagService
accounts *services.AccountService
+ users *services.UserService
}
// Initialize a transaction api singleton instance
@@ -26,6 +27,7 @@ var (
transactionCategories: services.TransactionCategories,
transactionTags: services.TransactionTags,
accounts: services.Accounts,
+ users: services.Users,
}
)
@@ -40,6 +42,16 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
}
uid := c.GetCurrentUid()
+ user, err := a.users.GetUserById(uid)
+
+ if err != nil {
+ if !errs.IsCustomError(err) {
+ log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get user, because %s", err.Error())
+ }
+
+ return nil, errs.ErrUserNotFound
+ }
+
var allCategoryIds []int64
if transactionListReq.CategoryId > 0 {
@@ -119,7 +131,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
}
- transactionEditable := transaction.IsEditable(allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
+ transactionEditable := transaction.IsEditable(user, transactionListReq.UtcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResps.Items[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
}
@@ -144,6 +156,16 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
}
uid := c.GetCurrentUid()
+ user, err := a.users.GetUserById(uid)
+
+ if err != nil {
+ if !errs.IsCustomError(err) {
+ log.ErrorfWithRequestId(c, "[transactions.TransactionMonthListHandler] failed to get user, because %s", err.Error())
+ }
+
+ return nil, errs.ErrUserNotFound
+ }
+
var allCategoryIds []int64
if transactionListReq.CategoryId > 0 {
@@ -213,7 +235,7 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
}
- transactionEditable := transaction.IsEditable(allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
+ transactionEditable := transaction.IsEditable(user, transactionListReq.UtcOffset, allAccounts[transaction.AccountId], allAccounts[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResps[i] = transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
}
@@ -232,6 +254,16 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
}
uid := c.GetCurrentUid()
+ user, err := a.users.GetUserById(uid)
+
+ if err != nil {
+ if !errs.IsCustomError(err) {
+ log.ErrorfWithRequestId(c, "[transactions.TransactionGetHandler] failed to get user, because %s", err.Error())
+ }
+
+ return nil, errs.ErrUserNotFound
+ }
+
transaction, err := a.transactions.GetTransactionByTransactionId(uid, transactionGetReq.Id)
if err != nil {
@@ -272,7 +304,7 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
return nil, errs.ErrOperationFailed
}
- transactionEditable := transaction.IsEditable(accountMap[transaction.AccountId], accountMap[transaction.RelatedAccountId])
+ transactionEditable := transaction.IsEditable(user, transactionGetReq.UtcOffset, accountMap[transaction.AccountId], accountMap[transaction.RelatedAccountId])
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
transactionResp := transaction.ToTransactionInfoResponse(transactionTagIds, transactionEditable)
@@ -320,7 +352,22 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (interface{}
}
uid := c.GetCurrentUid()
+ user, err := a.users.GetUserById(uid)
+
+ if err != nil {
+ if !errs.IsCustomError(err) {
+ log.ErrorfWithRequestId(c, "[transactions.TransactionCreateHandler] failed to get user, because %s", err.Error())
+ }
+
+ return nil, errs.ErrUserNotFound
+ }
+
transaction := a.createNewTransactionModel(uid, &transactionCreateReq)
+ transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, transactionCreateReq.UtcOffset)
+
+ if !transactionEditable {
+ return nil, errs.ErrCannotCreateTransactionWithThisTransactionTime
+ }
err = a.transactions.CreateTransaction(transaction, tagIds)
@@ -331,7 +378,7 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (interface{}
log.InfofWithRequestId(c, "[transactions.TransactionCreateHandler] user \"uid:%d\" has created a new transaction \"id:%d\" successfully", uid, transaction.TransactionId)
- transactionResp := transaction.ToTransactionInfoResponse(nil, true)
+ transactionResp := transaction.ToTransactionInfoResponse(tagIds, transactionEditable)
return transactionResp, nil
}
@@ -354,6 +401,16 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
}
uid := c.GetCurrentUid()
+ user, err := a.users.GetUserById(uid)
+
+ if err != nil {
+ if !errs.IsCustomError(err) {
+ log.ErrorfWithRequestId(c, "[transactions.TransactionModifyHandler] failed to get user, because %s", err.Error())
+ }
+
+ return nil, errs.ErrUserNotFound
+ }
+
transaction, err := a.transactions.GetTransactionByTransactionId(uid, transactionModifyReq.Id)
if err != nil {
@@ -409,6 +466,12 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
addTransactionTagIds = tagIds
}
+ transactionEditable := user.CanEditTransactionByTransactionTime(newTransaction.TransactionTime, transactionModifyReq.UtcOffset)
+
+ if !transactionEditable {
+ return nil, errs.ErrCannotModifyTransactionWithThisTransactionTime
+ }
+
err = a.transactions.ModifyTransaction(newTransaction, addTransactionTagIds, removeTransactionTagIds)
if err != nil {
@@ -419,7 +482,7 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
log.InfofWithRequestId(c, "[transactions.TransactionModifyHandler] user \"uid:%d\" has updated transaction \"id:%d\" successfully", uid, transactionModifyReq.Id)
newTransaction.Type = transaction.Type
- newTransactionResp := newTransaction.ToTransactionInfoResponse(tagIds, true)
+ newTransactionResp := newTransaction.ToTransactionInfoResponse(tagIds, transactionEditable)
return newTransactionResp, nil
}
diff --git a/pkg/api/users.go b/pkg/api/users.go
index 645d334a..0f60a8e9 100644
--- a/pkg/api/users.go
+++ b/pkg/api/users.go
@@ -45,12 +45,13 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (interface{}, *errs.Erro
userRegisterReq.Nickname = strings.TrimSpace(userRegisterReq.Nickname)
user := &models.User{
- Username: userRegisterReq.Username,
- Email: userRegisterReq.Email,
- Nickname: userRegisterReq.Nickname,
- Password: userRegisterReq.Password,
- DefaultCurrency: userRegisterReq.DefaultCurrency,
- FirstDayOfWeek: userRegisterReq.FirstDayOfWeek,
+ Username: userRegisterReq.Username,
+ Email: userRegisterReq.Email,
+ Nickname: userRegisterReq.Nickname,
+ Password: userRegisterReq.Password,
+ DefaultCurrency: userRegisterReq.DefaultCurrency,
+ FirstDayOfWeek: userRegisterReq.FirstDayOfWeek,
+ TransactionEditScope: models.TRANSACTION_EDIT_SCOPE_ALL,
}
err = a.users.CreateUser(user)
@@ -167,6 +168,14 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
userNew.FirstDayOfWeek = models.WEEKDAY_INVALID
}
+ if userUpdateReq.TransactionEditScope != nil && *userUpdateReq.TransactionEditScope != user.TransactionEditScope {
+ user.TransactionEditScope = *userUpdateReq.TransactionEditScope
+ userNew.TransactionEditScope = *userUpdateReq.TransactionEditScope
+ anythingUpdate = true
+ } else {
+ userNew.TransactionEditScope = models.TRANSACTION_EDIT_SCOPE_INVALID
+ }
+
if !anythingUpdate {
return nil, errs.ErrNothingWillBeUpdated
}
diff --git a/pkg/errs/transaction.go b/pkg/errs/transaction.go
index dada690e..a924deb1 100644
--- a/pkg/errs/transaction.go
+++ b/pkg/errs/transaction.go
@@ -18,4 +18,6 @@ var (
ErrCannotAddTransactionToHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 11, http.StatusBadRequest, "cannot add transaction to hidden account")
ErrCannotModifyTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 12, http.StatusBadRequest, "cannot modify transaction of hidden account")
ErrCannotDeleteTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 13, http.StatusBadRequest, "cannot delete transaction in hidden account")
+ ErrCannotCreateTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 14, http.StatusBadRequest, "cannot add transaction with this transaction time")
+ ErrCannotModifyTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 15, http.StatusBadRequest, "cannot edit transaction with this transaction time")
)
diff --git a/pkg/models/transaction.go b/pkg/models/transaction.go
index d8820bcc..46d5c464 100644
--- a/pkg/models/transaction.go
+++ b/pkg/models/transaction.go
@@ -62,6 +62,7 @@ type TransactionCreateRequest struct {
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"`
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
@@ -75,6 +76,7 @@ type TransactionModifyRequest struct {
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"`
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
@@ -86,6 +88,7 @@ type TransactionListByMaxTimeRequest struct {
MaxTime int64 `form:"max_time" binding:"min=0"`
MinTime int64 `form:"min_time" binding:"min=0"`
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
@@ -98,11 +101,13 @@ type TransactionListInMonthByPageRequest struct {
Keyword string `form:"keyword"`
Page int `form:"page" binding:"required,min=1"`
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
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
@@ -133,7 +138,11 @@ type TransactionInfoPageWrapperResponse struct {
}
// IsEditable returns whether this transaction can be edited
-func (t *Transaction) IsEditable(account *Account, relatedAccount *Account) bool {
+func (t *Transaction) IsEditable(currentUser *User, utcOffset int, account *Account, relatedAccount *Account) bool {
+ if currentUser == nil || !currentUser.CanEditTransactionByTransactionTime(t.TransactionTime, utcOffset) {
+ return false
+ }
+
if account == nil || account.Hidden {
return false
}
diff --git a/pkg/models/user.go b/pkg/models/user.go
index c9fb8fcf..914f42bf 100644
--- a/pkg/models/user.go
+++ b/pkg/models/user.go
@@ -1,5 +1,11 @@
package models
+import (
+ "time"
+
+ "github.com/mayswind/lab/pkg/utils"
+)
+
// UserType represents user type
type UserType byte
@@ -25,34 +31,51 @@ const (
WEEKDAY_INVALID WeekDay = 255
)
+// TransactionEditScope represents the scope which transaction can be edited
+type TransactionEditScope byte
+
+// Historical Transaction Edit Scopes
+const (
+ TRANSACTION_EDIT_SCOPE_NONE TransactionEditScope = 0
+ TRANSACTION_EDIT_SCOPE_ALL TransactionEditScope = 1
+ TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER TransactionEditScope = 2
+ TRANSACTION_EDIT_SCOPE_LAST_24H_OR_LATER TransactionEditScope = 3
+ TRANSACTION_EDIT_SCOPE_THIS_WEEK_OR_LATER TransactionEditScope = 4
+ TRANSACTION_EDIT_SCOPE_THIS_MONTH_OR_LATER TransactionEditScope = 5
+ TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER TransactionEditScope = 6
+ TRANSACTION_EDIT_SCOPE_INVALID TransactionEditScope = 255
+)
+
// User represents user data stored in database
type User struct {
- Uid int64 `xorm:"PK"`
- Username string `xorm:"VARCHAR(32) UNIQUE NOT NULL"`
- Email string `xorm:"VARCHAR(100) UNIQUE NOT NULL"`
- Nickname string `xorm:"VARCHAR(64) NOT NULL"`
- Password string `xorm:"VARCHAR(64) NOT NULL"`
- Salt string `xorm:"VARCHAR(10) NOT NULL"`
- Rands string `xorm:"VARCHAR(10) NOT NULL"`
- Type UserType `xorm:"TINYINT NOT NULL"`
- DefaultCurrency string `xorm:"VARCHAR(3) NOT NULL"`
- FirstDayOfWeek WeekDay `xorm:"TINYINT NOT NULL"`
- IsAdmin bool `xorm:"NOT NULL"`
- Deleted bool `xorm:"NOT NULL"`
- EmailVerified bool `xorm:"NOT NULL"`
- CreatedUnixTime int64
- UpdatedUnixTime int64
- DeletedUnixTime int64
- LastLoginUnixTime int64
+ Uid int64 `xorm:"PK"`
+ Username string `xorm:"VARCHAR(32) UNIQUE NOT NULL"`
+ Email string `xorm:"VARCHAR(100) UNIQUE NOT NULL"`
+ Nickname string `xorm:"VARCHAR(64) NOT NULL"`
+ Password string `xorm:"VARCHAR(64) NOT NULL"`
+ Salt string `xorm:"VARCHAR(10) NOT NULL"`
+ Rands string `xorm:"VARCHAR(10) NOT NULL"`
+ Type UserType `xorm:"TINYINT NOT NULL"`
+ DefaultCurrency string `xorm:"VARCHAR(3) NOT NULL"`
+ FirstDayOfWeek WeekDay `xorm:"TINYINT NOT NULL"`
+ TransactionEditScope TransactionEditScope `xorm:"TINYINT NOT NULL"`
+ IsAdmin bool `xorm:"NOT NULL"`
+ Deleted bool `xorm:"NOT NULL"`
+ EmailVerified bool `xorm:"NOT NULL"`
+ CreatedUnixTime int64
+ UpdatedUnixTime int64
+ DeletedUnixTime int64
+ LastLoginUnixTime int64
}
// UserBasicInfo represents a view-object of user basic info
type UserBasicInfo struct {
- Username string `json:"username"`
- Email string `json:"email"`
- Nickname string `json:"nickname"`
- DefaultCurrency string `json:"defaultCurrency"`
- FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
+ Username string `json:"username"`
+ Email string `json:"email"`
+ Nickname string `json:"nickname"`
+ DefaultCurrency string `json:"defaultCurrency"`
+ FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
+ TransactionEditScope TransactionEditScope `json:"transactionEditScope"`
}
// UserLoginRequest represents all parameters of user login request
@@ -73,12 +96,13 @@ type UserRegisterRequest struct {
// UserProfileUpdateRequest represents all parameters of user updating profile request
type UserProfileUpdateRequest struct {
- Email string `json:"email" binding:"omitempty,notBlank,max=100,validEmail"`
- Nickname string `json:"nickname" binding:"omitempty,notBlank,max=64"`
- Password string `json:"password" binding:"omitempty,min=6,max=128"`
- OldPassword string `json:"oldPassword" binding:"omitempty,min=6,max=128"`
- DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
- FirstDayOfWeek *WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
+ Email string `json:"email" binding:"omitempty,notBlank,max=100,validEmail"`
+ Nickname string `json:"nickname" binding:"omitempty,notBlank,max=64"`
+ Password string `json:"password" binding:"omitempty,min=6,max=128"`
+ OldPassword string `json:"oldPassword" binding:"omitempty,min=6,max=128"`
+ DefaultCurrency string `json:"defaultCurrency" binding:"omitempty,len=3,validCurrency"`
+ FirstDayOfWeek *WeekDay `json:"firstDayOfWeek" binding:"omitempty,min=0,max=6"`
+ TransactionEditScope *TransactionEditScope `json:"transactionEditScope" binding:"omitempty,min=0,max=7"`
}
// UserProfileUpdateResponse represents the data returns to frontend after updating profile
@@ -89,35 +113,80 @@ type UserProfileUpdateResponse struct {
// UserProfileResponse represents a view-object of user profile
type UserProfileResponse struct {
- Username string `json:"username"`
- Email string `json:"email"`
- Nickname string `json:"nickname"`
- Type UserType `json:"type"`
- DefaultCurrency string `json:"defaultCurrency"`
- FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
- LastLoginAt int64 `json:"lastLoginAt"`
+ Username string `json:"username"`
+ Email string `json:"email"`
+ Nickname string `json:"nickname"`
+ Type UserType `json:"type"`
+ DefaultCurrency string `json:"defaultCurrency"`
+ FirstDayOfWeek WeekDay `json:"firstDayOfWeek"`
+ TransactionEditScope TransactionEditScope `json:"transactionEditScope"`
+ LastLoginAt int64 `json:"lastLoginAt"`
+}
+
+// CanEditTransactionByTransactionTime returns whether this user can edit transaction with specified transaction time
+func (u *User) CanEditTransactionByTransactionTime(transactionTime int64, utcOffset int) bool {
+ if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_NONE {
+ return false
+ } else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_ALL {
+ return true
+ }
+
+ now := time.Now()
+
+ transactionUnixTime := utils.GetUnixTimeFromTransactionTime(transactionTime)
+
+ if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_LAST_24H_OR_LATER {
+ return transactionUnixTime >= now.Unix()-24*60*60
+ }
+
+ _, serverUtcOffset := now.Zone()
+ serverTodayFirstUnixTime := now.Unix() - int64(now.Hour()*60*60+now.Minute()*60+now.Second())
+ clientTodayFirstUnixTime := serverTodayFirstUnixTime + int64(utcOffset*60-serverUtcOffset)
+
+ if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_TODAY_OR_LATER {
+ return transactionUnixTime >= clientTodayFirstUnixTime
+ } else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_WEEK_OR_LATER {
+ dayOfWeek := int(now.Weekday()) - int(u.FirstDayOfWeek)
+
+ if dayOfWeek < 0 {
+ dayOfWeek += 7
+ }
+
+ clientWeekFirstUnixTime := clientTodayFirstUnixTime - int64(dayOfWeek*24*60*60)
+ return transactionUnixTime >= clientWeekFirstUnixTime
+ } else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_MONTH_OR_LATER {
+ clientMonthFirstUnixTime := clientTodayFirstUnixTime - int64((now.Day()-1)*24*60*60)
+ return transactionUnixTime >= clientMonthFirstUnixTime
+ } else if u.TransactionEditScope == TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
+ clientYearFirstUnixTime := clientTodayFirstUnixTime - int64((now.YearDay()-1)*24*60*60)
+ return transactionUnixTime >= clientYearFirstUnixTime
+ }
+
+ return false
}
// ToUserBasicInfo returns a user basic view-object according to database model
func (u *User) ToUserBasicInfo() *UserBasicInfo {
return &UserBasicInfo{
- Username: u.Username,
- Email: u.Email,
- Nickname: u.Nickname,
- DefaultCurrency: u.DefaultCurrency,
- FirstDayOfWeek: u.FirstDayOfWeek,
+ Username: u.Username,
+ Email: u.Email,
+ Nickname: u.Nickname,
+ DefaultCurrency: u.DefaultCurrency,
+ FirstDayOfWeek: u.FirstDayOfWeek,
+ TransactionEditScope: u.TransactionEditScope,
}
}
// ToUserProfileResponse returns a user profile view-object according to database model
func (u *User) ToUserProfileResponse() *UserProfileResponse {
return &UserProfileResponse{
- Username: u.Username,
- Email: u.Email,
- Nickname: u.Nickname,
- Type: u.Type,
- DefaultCurrency: u.DefaultCurrency,
- FirstDayOfWeek: u.FirstDayOfWeek,
- LastLoginAt: u.LastLoginUnixTime,
+ Username: u.Username,
+ Email: u.Email,
+ Nickname: u.Nickname,
+ Type: u.Type,
+ DefaultCurrency: u.DefaultCurrency,
+ FirstDayOfWeek: u.FirstDayOfWeek,
+ TransactionEditScope: u.TransactionEditScope,
+ LastLoginAt: u.LastLoginUnixTime,
}
}
diff --git a/pkg/services/users.go b/pkg/services/users.go
index 6ebbb044..73db01ca 100644
--- a/pkg/services/users.go
+++ b/pkg/services/users.go
@@ -198,6 +198,10 @@ func (s *UserService) UpdateUser(user *models.User) (keyProfileUpdated bool, err
updateCols = append(updateCols, "first_day_of_week")
}
+ if models.TRANSACTION_EDIT_SCOPE_NONE <= user.TransactionEditScope && user.TransactionEditScope <= models.TRANSACTION_EDIT_SCOPE_THIS_YEAR_OR_LATER {
+ updateCols = append(updateCols, "transaction_edit_scope")
+ }
+
user.UpdatedUnixTime = now
updateCols = append(updateCols, "updated_unix_time")
diff --git a/src/lib/services.js b/src/lib/services.js
index f970c80f..d09f3689 100644
--- a/src/lib/services.js
+++ b/src/lib/services.js
@@ -2,6 +2,7 @@ import axios from 'axios';
import api from "../consts/api.js";
import userState from "./userstate.js";
+import utils from "./utils.js";
let needBlockRequest = false;
let blockedRequests = [];
@@ -130,14 +131,15 @@ export default {
getProfile: () => {
return axios.get('v1/users/profile/get.json');
},
- updateProfile: ({ email, nickname, password, oldPassword, defaultCurrency, firstDayOfWeek }) => {
+ updateProfile: ({ email, nickname, password, oldPassword, defaultCurrency, firstDayOfWeek, transactionEditScope }) => {
return axios.post('v1/users/profile/update.json', {
email,
nickname,
password,
oldPassword,
defaultCurrency,
- firstDayOfWeek
+ firstDayOfWeek,
+ transactionEditScope
});
},
get2FAStatus: () => {
@@ -249,12 +251,14 @@ export default {
});
},
getTransactions: ({ maxTime, minTime, type, categoryId, accountId, keyword }) => {
- 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`);
+ 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&utc_offset=${utcOffset}`);
},
getTransaction: ({ id }) => {
- return axios.get('v1/transactions/get.json?id=' + id);
+ const utcOffset = utils.getTimezoneOffsetMinutes();
+ return axios.get(`v1/transactions/get.json?id=${id}&utc_offset=${utcOffset}`);
},
- addTransaction: ({ type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment }) => {
+ addTransaction: ({ type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment, utcOffset }) => {
return axios.post('v1/transactions/add.json', {
type,
categoryId,
@@ -264,10 +268,11 @@ export default {
sourceAmount,
destinationAmount,
tagIds,
- comment
+ comment,
+ utcOffset
});
},
- modifyTransaction: ({ id, type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment }) => {
+ modifyTransaction: ({ id, type, categoryId, time, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, tagIds, comment, utcOffset }) => {
return axios.post('v1/transactions/modify.json', {
id,
type,
@@ -278,7 +283,8 @@ export default {
sourceAmount,
destinationAmount,
tagIds,
- comment
+ comment,
+ utcOffset
});
},
deleteTransaction: ({ id }) => {
diff --git a/src/lib/utils.js b/src/lib/utils.js
index b7c7e992..a40e93d5 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -42,6 +42,22 @@ function getTimezoneOffset(timezone) {
}
}
+function getTimezoneOffsetMinutes(timezone) {
+ const offset = getTimezoneOffset(timezone);
+
+ if (!offset) {
+ return 0;
+ }
+
+ const parts = offset.split(':');
+
+ if (parts.length !== 2) {
+ return 0;
+ }
+
+ return parseInt(parts[0]) * 60 + parseInt(parts[1]);
+}
+
function getCurrentUnixTime() {
return moment().unix();
}
@@ -571,6 +587,7 @@ export default {
isNumber,
isBoolean,
getTimezoneOffset,
+ getTimezoneOffsetMinutes,
getCurrentUnixTime,
parseDateFromUnixTime,
formatUnixTime,
diff --git a/src/locales/en.js b/src/locales/en.js
index 6c724431..7c6550d2 100644
--- a/src/locales/en.js
+++ b/src/locales/en.js
@@ -546,6 +546,8 @@ export default {
'cannot add transaction to hidden account': 'You cannot add transaction to an hidden account',
'cannot modify transaction of hidden account': 'You cannot modify transaction of an hidden account',
'cannot delete transaction in hidden account': 'You cannot delete transaction in an hidden account',
+ 'cannot add transaction with this transaction time': 'You cannot add transaction with this transaction time',
+ 'cannot modify transaction with this transaction time ': 'You cannot modify this transaction with this transaction time',
'transaction category id is invalid': 'Transaction category ID is invalid',
'transaction category not found': 'Transaction category is not found',
'transaction category type is invalid': 'Transaction category type is invalid',
@@ -571,6 +573,7 @@ export default {
'oldPassword': 'Current Password',
'defaultCurrency': 'Default Currency',
'firstDayOfWeek': 'First Day of Week',
+ 'transactionEditScope': 'Transaction Edit Scope',
'name': 'Name',
'category': 'Category',
'type': 'Type',
@@ -678,6 +681,12 @@ export default {
'Your nickname': 'Your nickname',
'Default Currency': 'Default Currency',
'First Day of Week': 'First Day of Week',
+ 'Transaction Edit Scope': 'Transaction Edit Scope',
+ 'Today or later': 'Today or later',
+ 'Recent 24 hours or later': 'Recent 24 hours or later',
+ 'This week or later': 'This week or later',
+ 'This month or later': 'This month or later',
+ 'This year or later': 'This year or later',
'Log In': 'Log In',
'Don\'t have an account?': 'Don\'t have an account?',
'Create an account': 'Create an account',
diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js
index 82153b11..035854cf 100644
--- a/src/locales/zh_Hans.js
+++ b/src/locales/zh_Hans.js
@@ -546,6 +546,8 @@ export default {
'cannot add transaction to hidden account': '您不能在隐藏账户中添加交易',
'cannot modify transaction of hidden account': '您不能修改隐藏账户中的交易',
'cannot delete transaction in hidden account': '您不能删除隐藏账户中的交易',
+ 'cannot add transaction with this transaction time': '您不能添加有该交易时间的交易',
+ 'cannot modify transaction with this transaction time ': '您不能修改有该交易时间的交易',
'transaction category id is invalid': '交易分类ID无效',
'transaction category not found': '交易分类不存在',
'transaction category type is invalid': '交易分类类型无效',
@@ -571,6 +573,7 @@ export default {
'oldPassword': '当前密码',
'defaultCurrency': '默认货币',
'firstDayOfWeek': '每周第一天',
+ 'transactionEditScope': '交易编辑范围',
'name': '名称',
'category': '分类',
'type': '类型',
@@ -678,6 +681,12 @@ export default {
'Your nickname': '你的昵称',
'Default Currency': '默认货币',
'First Day of Week': '每周第一天',
+ 'Transaction Edit Scope': '交易编辑范围',
+ 'Today or later': '今天或更晚',
+ 'Recent 24 hours or later': '最近24小时或更晚',
+ 'This week or later': '本周或更晚',
+ 'This month or later': '本月或更晚',
+ 'This year or later': '今年或更晚',
'Log In': '登录',
'Don\'t have an account?': '还没有账号?',
'Create an account': '创建新账号',
diff --git a/src/store/user.js b/src/store/user.js
index 4618c53a..8e3f0425 100644
--- a/src/store/user.js
+++ b/src/store/user.js
@@ -236,7 +236,8 @@ export function updateUserProfile(context, { profile, currentPassword }) {
email: profile.email,
nickname: profile.nickname,
defaultCurrency: profile.defaultCurrency,
- firstDayOfWeek: profile.firstDayOfWeek
+ firstDayOfWeek: profile.firstDayOfWeek,
+ transactionEditScope: profile.transactionEditScope
}).then(response => {
const data = response.data;
diff --git a/src/views/mobile/transactions/Edit.vue b/src/views/mobile/transactions/Edit.vue
index 77701543..f8ffbad2 100644
--- a/src/views/mobile/transactions/Edit.vue
+++ b/src/views/mobile/transactions/Edit.vue
@@ -662,7 +662,8 @@ export default {
destinationAccountId: '0',
destinationAmount: 0,
tagIds: self.transaction.tagIds,
- comment: self.transaction.comment
+ comment: self.transaction.comment,
+ utcOffset: self.$utilities.getTimezoneOffsetMinutes()
};
if (self.transaction.type === self.$constants.transaction.allTransactionTypes.Expense) {
diff --git a/src/views/mobile/users/UserProfile.vue b/src/views/mobile/users/UserProfile.vue
index de14d35b..42090b0e 100644
--- a/src/views/mobile/users/UserProfile.vue
+++ b/src/views/mobile/users/UserProfile.vue
@@ -86,6 +86,21 @@
+
+
+
+
@@ -112,13 +127,15 @@ export default {
email: '',
nickname: '',
defaultCurrency: '',
- firstDayOfWeek: 0
+ firstDayOfWeek: 0,
+ transactionEditScope: 1
},
oldProfile: {
email: '',
nickname: '',
defaultCurrency: '',
- firstDayOfWeek: 0
+ firstDayOfWeek: 0,
+ transactionEditScope: 1
},
currentPassword: '',
loading: true,
@@ -147,7 +164,8 @@ export default {
this.newProfile.email === this.oldProfile.email &&
this.newProfile.nickname === this.oldProfile.nickname &&
this.newProfile.defaultCurrency === this.oldProfile.defaultCurrency &&
- this.newProfile.firstDayOfWeek === this.oldProfile.firstDayOfWeek) {
+ this.newProfile.firstDayOfWeek === this.oldProfile.firstDayOfWeek &&
+ this.newProfile.transactionEditScope === this.oldProfile.transactionEditScope) {
return 'Nothing has been modified';
} else if (!this.newProfile.password && this.newProfile.confirmPassword) {
return 'Password cannot be empty';
@@ -181,11 +199,13 @@ export default {
self.oldProfile.nickname = profile.nickname;
self.oldProfile.defaultCurrency = profile.defaultCurrency;
self.oldProfile.firstDayOfWeek = profile.firstDayOfWeek;
+ self.oldProfile.transactionEditScope = profile.transactionEditScope;
self.newProfile.email = self.oldProfile.email
self.newProfile.nickname = self.oldProfile.nickname;
self.newProfile.defaultCurrency = self.oldProfile.defaultCurrency;
self.newProfile.firstDayOfWeek = self.oldProfile.firstDayOfWeek;
+ self.newProfile.transactionEditScope = self.oldProfile.transactionEditScope;
self.loading = false;
}).catch(error => {