Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
kresusapp
kresus
Commits
c7f091e2
Commit
c7f091e2
authored
Dec 20, 2016
by
Benjamin Bouvier
Browse files
Server: document models a bit more.
parent
0408d563
Pipeline
#10285
passed with stage
in 3 minutes and 15 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
server/lib/accounts-manager.js
View file @
c7f091e2
...
...
@@ -239,9 +239,9 @@ merging as per request`);
operation
.
date
=
operation
.
date
||
now
;
operation
.
dateImport
=
now
;
let
operationType
=
OperationType
.
getNameFromWeboobId
(
sourceOp
.
type
);
let
operationType
=
OperationType
.
idToName
(
sourceOp
.
type
);
// The default
value of the type is set
directly by the operation model
// The default
type's value is
directly
set
by the operation model
.
if
(
operationType
!==
null
)
operation
.
type
=
operationType
;
...
...
server/lib/alert-manager.js
View file @
c7f091e2
import
Emailer
from
'
./emailer
'
;
import
Notifications
from
'
./notifications
'
;
import
Account
from
'
../models/account
'
;
import
Alert
from
'
../models/alert
'
;
import
Config
from
'
../models/config
'
;
import
Account
from
'
../models/account
'
;
import
Alert
from
'
../models/alert
'
;
import
Config
from
'
../models/config
'
;
import
{
makeLogger
,
translate
as
$t
,
currency
}
from
'
../helpers
'
;
...
...
@@ -53,7 +53,7 @@ ${$t('server.email.signature')}
for
(
let
a
of
accounts
)
{
accountsMap
.
set
(
a
.
accountNumber
,
{
title
:
a
.
title
,
format
ter
:
currency
.
makeFormat
(
a
.
currency
||
defaultCurrency
)
format
Currency
:
currency
.
makeFormat
(
a
.
currency
||
defaultCurrency
)
});
}
...
...
@@ -65,8 +65,7 @@ ${$t('server.email.signature')}
// Memoize alerts by account
let
alerts
;
if
(
!
alertsByAccount
.
has
(
operation
.
bankAccount
))
{
alerts
=
await
Alert
.
byAccountAndType
(
operation
.
bankAccount
,
'
transaction
'
);
alerts
=
await
Alert
.
byAccountAndType
(
operation
.
bankAccount
,
'
transaction
'
);
alertsByAccount
.
set
(
operation
.
bankAccount
,
alerts
);
}
else
{
alerts
=
alertsByAccount
.
get
(
operation
.
bankAccount
);
...
...
@@ -78,14 +77,13 @@ ${$t('server.email.signature')}
}
// Set the account information
let
{
title
:
accountName
,
format
ter
}
=
accountsMap
.
get
(
operation
.
bankAccount
);
let
{
title
:
accountName
,
format
Currency
}
=
accountsMap
.
get
(
operation
.
bankAccount
);
for
(
let
alert
of
alerts
)
{
if
(
!
alert
.
testTransaction
(
operation
))
continue
;
let
text
=
alert
.
formatOperationMessage
(
operation
,
accountName
,
formatter
);
let
text
=
alert
.
formatOperationMessage
(
operation
,
accountName
,
formatCurrency
);
await
this
.
send
({
subject
:
$t
(
'
server.alert.operation.title
'
),
text
...
...
@@ -114,9 +112,8 @@ ${$t('server.email.signature')}
// Set the currency formatter
let
curr
=
account
.
currency
||
defaultCurrency
;
let
currencyFormatter
=
currency
.
makeFormat
(
curr
);
let
text
=
alert
.
formatAccountMessage
(
account
.
title
,
balance
,
currencyFormatter
);
let
formatCurrency
=
currency
.
makeFormat
(
curr
);
let
text
=
alert
.
formatAccountMessage
(
account
.
title
,
balance
,
formatCurrency
);
await
this
.
send
({
subject
:
$t
(
'
server.alert.balance.title
'
),
text
...
...
server/models/access.js
View file @
c7f091e2
import
*
as
americano
from
'
cozydb
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
}
from
'
../helpers
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
}
from
'
../helpers
'
;
let
log
=
makeLogger
(
'
models/access
'
);
let
Access
=
americano
.
getModel
(
'
bankaccess
'
,
{
//
Weboob module name
//
External (backend) unique identifier.
bank
:
String
,
// Credentials to connect to the bank's website.
login
:
String
,
password
:
String
,
// Any supplementary fields necessary to connect to the bank's website.
customFields
:
String
,
// Text status indicating whether the last poll was successful or not.
fetchStatus
:
{
type
:
String
,
default
:
'
OK
'
},
// Don't use! Only used to migrate data
// ************************************************************************
// DEPRECATED.
// ************************************************************************
website
:
String
,
_passwordStillEncrypted
:
Boolean
});
...
...
@@ -27,8 +37,9 @@ Access = promisifyModel(Access);
let
request
=
promisify
(::
Access
.
request
);
Access
.
byBank
=
async
function
byBank
(
bank
)
{
if
(
typeof
bank
!==
'
object
'
||
typeof
bank
.
uuid
!==
'
string
'
)
if
(
typeof
bank
!==
'
object
'
||
typeof
bank
.
uuid
!==
'
string
'
)
{
log
.
warn
(
'
Access.byBank misuse: bank must be a Bank instance.
'
);
}
let
params
=
{
key
:
bank
.
uuid
...
...
@@ -52,18 +63,16 @@ Access.allLike = async function allLike(access) {
// Sync function
Access
.
prototype
.
hasPassword
=
function
()
{
return
(
typeof
this
.
_passwordStillEncrypted
===
'
undefined
'
||
!
this
.
_passwordStillEncrypted
)
&&
// Can happen after import of kresus data
return
(
typeof
this
.
_passwordStillEncrypted
===
'
undefined
'
||
!
this
.
_passwordStillEncrypted
)
&&
typeof
this
.
password
!==
'
undefined
'
;
};
// Can the access be polled
Access
.
prototype
.
canBePolled
=
function
()
{
return
this
.
fetchStatus
!==
'
INVALID_PASSWORD
'
&&
this
.
fetchStatus
!==
'
EXPIRED_PASSWORD
'
&&
this
.
fetchStatus
!==
'
INVALID_PARAMETERS
'
&&
this
.
fetchStatus
!==
'
NO_PASSWORD
'
;
this
.
fetchStatus
!==
'
EXPIRED_PASSWORD
'
&&
this
.
fetchStatus
!==
'
INVALID_PARAMETERS
'
&&
this
.
fetchStatus
!==
'
NO_PASSWORD
'
;
};
module
.
exports
=
Access
;
server/models/account.js
View file @
c7f091e2
...
...
@@ -6,32 +6,41 @@ import Operation from './operation';
let
log
=
makeLogger
(
'
models/account
'
);
let
Account
=
americano
.
getModel
(
'
bankaccount
'
,
{
// Unique bank module identifier, which determines which source to use.
// ************************************************************************
// EXTERNAL LINKS
// ************************************************************************
// External (backend) bank module identifier, determining which source to use.
// TODO could be removed, since this is in the linked access?
bank
:
String
,
//
Primary key: i
d of the bankaccess instance.
//
I
d of the bankaccess instance.
bankAccess
:
String
,
// Account number provided by the source. Acts as an id for other models.
accountNumber
:
String
,
// ************************************************************************
// ACCOUNT INFORMATION
// ************************************************************************
// Date at which the account has been imported.
importDate
:
Date
,
//
Label provided by the source
.
title
:
String
,
//
Amount on the account, at the date at which it has been imported
.
initialAmount
:
Number
,
// Account number provided by the source.
accountNumber
:
String
,
// Date at which the account has been polled for the last time.
lastChecked
:
Date
,
// Label describing the account provided by the source.
title
:
String
,
// IBAN provided by the source (facultative).
iban
:
String
,
// Currency used by the account.
currency
:
String
,
// Initial amount on the account.
initialAmount
:
Number
,
// Date at which the account has been polled for the last time.
lastChecked
:
Date
currency
:
String
});
Account
=
promisifyModel
(
Account
);
...
...
@@ -39,8 +48,9 @@ Account = promisifyModel(Account);
let
request
=
promisify
(::
Account
.
request
);
Account
.
byBank
=
async
function
byBank
(
bank
)
{
if
(
typeof
bank
!==
'
object
'
||
typeof
bank
.
uuid
!==
'
string
'
)
if
(
typeof
bank
!==
'
object
'
||
typeof
bank
.
uuid
!==
'
string
'
)
{
log
.
warn
(
'
Account.byBank misuse: bank must be a Bank instance
'
);
}
let
params
=
{
key
:
bank
.
uuid
...
...
@@ -49,10 +59,12 @@ Account.byBank = async function byBank(bank) {
};
Account
.
findMany
=
async
function
findMany
(
accountIds
)
{
if
(
!
(
accountIds
instanceof
Array
))
if
(
!
(
accountIds
instanceof
Array
))
{
log
.
warn
(
'
Account.findMany misuse: accountIds must be an Array
'
);
if
(
accountIds
.
length
&&
typeof
accountIds
[
0
]
!==
'
string
'
)
}
if
(
accountIds
.
length
&&
typeof
accountIds
[
0
]
!==
'
string
'
)
{
log
.
warn
(
'
Account.findMany misuse: accountIds must be a [String]
'
);
}
let
params
=
{
keys
:
accountIds
.
slice
()
...
...
@@ -61,8 +73,9 @@ Account.findMany = async function findMany(accountIds) {
};
Account
.
byAccountNumber
=
async
function
byAccountNumber
(
accountNumber
)
{
if
(
typeof
accountNumber
!==
'
string
'
)
if
(
typeof
accountNumber
!==
'
string
'
)
{
log
.
warn
(
'
Account.byAccountNumber misuse: 1st param must be a string
'
);
}
let
params
=
{
key
:
accountNumber
...
...
@@ -71,8 +84,9 @@ Account.byAccountNumber = async function byAccountNumber(accountNumber) {
};
Account
.
byAccess
=
async
function
byAccess
(
access
)
{
if
(
typeof
access
!==
'
object
'
||
typeof
access
.
id
!==
'
string
'
)
if
(
typeof
access
!==
'
object
'
||
typeof
access
.
id
!==
'
string
'
)
{
log
.
warn
(
'
Account.byAccess misuse: access must be an Access instance
'
);
}
let
params
=
{
key
:
access
.
id
...
...
server/models/alert.js
View file @
c7f091e2
import
*
as
americano
from
'
cozydb
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
translate
as
$t
,
formatDateToLocaleString
}
from
'
../helpers
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
translate
as
$t
,
formatDateToLocaleString
}
from
'
../helpers
'
;
let
log
=
makeLogger
(
'
models/alert
'
);
let
Alert
=
americano
.
getModel
(
'
bankalert
'
,
{
// external (backend) account id
// external (backend) account id
.
bankAccount
:
String
,
// possible options are: report, balance, transaction
// possible options are: report, balance, transaction
.
type
:
String
,
// only for reports : daily, weekly, monthly
// only for reports : daily, weekly, monthly
.
frequency
:
String
,
// only for balance/transaction
// only for balance/transaction
.
limit
:
Number
,
// only for balance/transaction: gt, lt
// only for balance/transaction: gt, lt
.
order
:
String
,
//
date of
last
alert
//
when did the alert get triggered for the
last
time?
lastTriggeredDate
:
Date
});
...
...
@@ -30,8 +36,9 @@ let request = promisify(::Alert.request);
let
requestDestroy
=
promisify
(::
Alert
.
requestDestroy
);
Alert
.
byAccount
=
async
function
byAccount
(
account
)
{
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
id
!==
'
string
'
)
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
id
!==
'
string
'
)
{
log
.
warn
(
'
Alert.byAccount misuse: account must be an Account instance
'
);
}
let
params
=
{
key
:
account
.
id
...
...
@@ -40,10 +47,12 @@ Alert.byAccount = async function byAccount(account) {
};
Alert
.
byAccountAndType
=
async
function
byAccountAndType
(
accountID
,
type
)
{
if
(
typeof
accountID
!==
'
string
'
)
if
(
typeof
accountID
!==
'
string
'
)
{
log
.
warn
(
'
Alert.byAccountAndType misuse: accountID must be a string
'
);
if
(
typeof
type
!==
'
string
'
)
}
if
(
typeof
type
!==
'
string
'
)
{
log
.
warn
(
'
Alert.byAccountAndType misuse: type must be a string
'
);
}
let
params
=
{
key
:
[
accountID
,
type
]
...
...
@@ -52,8 +61,9 @@ Alert.byAccountAndType = async function byAccountAndType(accountID, type) {
};
Alert
.
reportsByFrequency
=
async
function
reportsByFrequency
(
frequency
)
{
if
(
typeof
frequency
!==
'
string
'
)
if
(
typeof
frequency
!==
'
string
'
)
{
log
.
warn
(
'
Alert.reportsByFrequency misuse: frequency must be a string
'
);
}
let
params
=
{
key
:
[
'
report
'
,
frequency
]
...
...
@@ -62,8 +72,9 @@ Alert.reportsByFrequency = async function reportsByFrequency(frequency) {
};
Alert
.
destroyByAccount
=
async
function
destroyByAccount
(
id
)
{
if
(
typeof
id
!==
'
string
'
)
if
(
typeof
id
!==
'
string
'
)
{
log
.
warn
(
"
Alert.destroyByAccount API misuse: id isn't a string
"
);
}
let
params
=
{
key
:
id
,
...
...
@@ -75,8 +86,9 @@ Alert.destroyByAccount = async function destroyByAccount(id) {
// Sync function
Alert
.
prototype
.
testTransaction
=
function
(
operation
)
{
if
(
this
.
type
!==
'
transaction
'
)
if
(
this
.
type
!==
'
transaction
'
)
{
return
false
;
}
let
alertLimit
=
+
this
.
limit
;
let
amount
=
Math
.
abs
(
operation
.
amount
);
...
...
@@ -86,42 +98,47 @@ Alert.prototype.testTransaction = function(operation) {
// Sync function
Alert
.
prototype
.
testBalance
=
function
(
balance
)
{
if
(
this
.
type
!==
'
balance
'
)
if
(
this
.
type
!==
'
balance
'
)
{
return
false
;
}
let
alertLimit
=
+
this
.
limit
;
return
(
this
.
order
===
'
lt
'
&&
balance
<=
alertLimit
)
||
(
this
.
order
===
'
gt
'
&&
balance
>=
alertLimit
);
};
Alert
.
prototype
.
formatOperationMessage
=
function
(
operation
,
accountName
,
currencyFormatter
)
{
Alert
.
prototype
.
formatOperationMessage
=
function
(
operation
,
accountName
,
formatCurrency
)
{
let
cmp
=
this
.
order
===
'
lt
'
?
$t
(
'
server.alert.operation.lessThan
'
)
:
$t
(
'
server.alert.operation.greaterThan
'
);
let
amount
=
currencyFormatter
(
operation
.
amount
);
let
account
=
accountName
;
let
title
=
operation
.
title
;
let
amount
=
formatCurrency
(
operation
.
amount
);
let
date
=
formatDateToLocaleString
(
operation
.
date
);
let
limit
=
formatCurrency
(
this
.
limit
);
return
$t
(
'
server.alert.operation.content
'
,
{
title
,
account
,
title
:
operation
.
title
,
account
:
accountName
,
amount
,
cmp
,
date
,
limit
:
currencyFormatter
(
this
.
limit
)
limit
});
};
Alert
.
prototype
.
formatAccountMessage
=
function
(
title
,
balance
,
currencyFormatter
)
{
Alert
.
prototype
.
formatAccountMessage
=
function
(
title
,
balance
,
formatCurrency
)
{
let
cmp
=
this
.
order
===
'
lt
'
?
$t
(
'
server.alert.balance.lessThan
'
)
:
$t
(
'
server.alert.balance.greaterThan
'
);
let
limit
=
formatCurrency
(
this
.
limit
);
let
formattedBalance
=
formatCurrency
(
balance
);
return
$t
(
'
server.alert.balance.content
'
,
{
title
,
cmp
,
limit
:
currencyFormatter
(
this
.
limit
)
,
balance
:
currencyF
ormatte
r
(
b
alance
)
limit
,
balance
:
f
ormatte
dB
alance
});
};
...
...
server/models/category.js
View file @
c7f091e2
...
...
@@ -2,15 +2,15 @@ import * as americano from 'cozydb';
import
{
promisifyModel
}
from
'
../helpers
'
;
let
Category
=
americano
.
getModel
(
'
bankcategory
'
,
{
// Internal category id.
parentId
:
String
,
// Label of the category.
title
:
String
,
// Hexadecimal RGB format.
color
:
String
,
// Internal category id.
parentId
:
String
,
// Threshold used in the budget section, defined by the user.
threshold
:
{
type
:
Number
,
...
...
server/models/config.js
View file @
c7f091e2
import
*
as
americano
from
'
cozydb
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
KError
}
from
'
../helpers
'
;
import
{
testInstall
,
getVersion
as
getWeboobVersion
}
from
'
../lib/sources/weboob
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
KError
}
from
'
../helpers
'
;
import
{
testInstall
,
getVersion
as
getWeboobVersion
}
from
'
../lib/sources/weboob
'
;
import
DefaultSettings
from
'
../shared/default-settings
'
;
let
log
=
makeLogger
(
'
models/config
'
);
// A simple key/value configuration pair.
let
Config
=
americano
.
getModel
(
'
kresusconfig
'
,
{
name
:
String
,
value
:
String
...
...
@@ -16,17 +26,20 @@ Config = promisifyModel(Config);
let
request
=
promisify
(::
Config
.
request
);
// Returns a pair {name, value}
// Returns a pair {name, value}
or null if not found.
Config
.
byName
=
async
function
byName
(
name
)
{
if
(
typeof
name
!==
'
string
'
)
if
(
typeof
name
!==
'
string
'
)
{
log
.
warn
(
'
Config.byName misuse: name must be a string
'
);
}
let
founds
=
await
request
(
'
byName
'
,
{
key
:
name
});
if
(
founds
&&
founds
.
length
)
return
founds
[
0
];
return
null
;
};
// Returns a pair {name, value}
// Returns a pair {name, value}
or the default value if not found.
async
function
findOrCreateByName
(
name
,
defaultValue
)
{
let
found
=
await
request
(
'
byName
'
,
{
key
:
name
});
if
(
!
found
||
!
found
.
length
)
{
...
...
@@ -41,16 +54,18 @@ async function findOrCreateByName(name, defaultValue) {
}
Config
.
findOrCreateByName
=
findOrCreateByName
;
// Returns a pair {name, value}
// Returns a pair {name, value}
or the preset default value if not found.
async
function
findOrCreateDefault
(
name
)
{
if
(
!
DefaultSettings
.
has
(
name
))
if
(
!
DefaultSettings
.
has
(
name
))
{
throw
new
KError
(
`Setting
${
name
}
has no default value!`
);
}
let
defaultValue
=
DefaultSettings
.
get
(
name
);
return
await
findOrCreateByName
(
name
,
defaultValue
);
}
Config
.
findOrCreateDefault
=
findOrCreateDefault
;
// Returns
the
boolean value
// Returns
a
boolean value
for a given key, or the preset default.
async
function
findOrCreateDefaultBooleanValue
(
name
)
{
let
pair
=
await
findOrCreateDefault
(
name
);
return
pair
.
value
===
'
true
'
;
...
...
server/models/operation.js
View file @
c7f091e2
import
*
as
americano
from
'
cozydb
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
UNKNOWN_OPERATION_TYPE
}
from
'
../helpers
'
;
import
{
makeLogger
,
promisify
,
promisifyModel
,
UNKNOWN_OPERATION_TYPE
}
from
'
../helpers
'
;
let
log
=
makeLogger
(
'
models/operations
'
);
// Whenever you're adding something to the model, don't forget to modify
// Operation.prototype.merge
From. Also, this should be kept in sync with the
// merging of operations on the client side.
// Operation.prototype.merge
With.
let
Operation
=
americano
.
getModel
(
'
bankoperation
'
,
{
// external (backend) account id
// ************************************************************************
// EXTERNAL LINKS
// ************************************************************************
// external (backend) account id.
bankAccount
:
String
,
// internal id
// internal
category
id
.
categoryId
:
String
,
// external (backend) type id or UNKNOWN_OPERATION_TYPE.
type
:
{
type
:
String
,
default
:
UNKNOWN_OPERATION_TYPE
},
// ************************************************************************
// TEXT FIELDS
// ************************************************************************
// short summary of what the operation is about.
title
:
String
,
date
:
Date
,
// long description of what the operation is about.
raw
:
String
,
amount
:
Number
,
// description entered by the user.
customLabel
:
String
,
raw
:
String
,
// ************************************************************************
// DATE FIELDS
// ************************************************************************
// date at which the operation has been processed by the backend.
date
:
Date
,
// date at which the operation has been imported into kresus.
dateImport
:
Date
,
customLabel
:
String
,
// ************************************************************************
// OTHER TRANSACTION FIELDS
// ************************************************************************
// Tell if the user has created the operation by itself, or if weboob did.
// amount of the operation, in a certain currency.
amount
:
Number
,
// whether the user has created the operation by itself, or if the backend
// did.
createdByUser
:
Boolean
,
// ************************************************************************
// ATTACHMENTS
// ************************************************************************
// TODO: remove linkPlainEnglish?
// {linkTranslationKey: String, linkPlainEnglish: String, url: String}
attachments
:
Object
,
// TODO merge with attachments?
// Binary is an object containing one field (file) that links to a binary
// document via an id. The binary document has a binary file
// as attachment.
binary
:
x
=>
x
,
// internal id
// Kept for backward compatibility
// ************************************************************************
// DEPRECATED
// ************************************************************************
// internal operation type id.
operationTypeID
:
String
});
...
...
@@ -53,8 +91,7 @@ let request = promisify(::Operation.request);
let
requestDestroy
=
promisify
(::
Operation
.
requestDestroy
);
Operation
.
byAccount
=
async
function
byAccount
(
account
)
{
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
accountNumber
!==
'
string
'
)
{
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
accountNumber
!==
'
string
'
)
{
log
.
warn
(
'
Operation.byAccount misuse: account must be an Account
'
);
}
...
...
@@ -65,8 +102,9 @@ Operation.byAccount = async function byAccount(account) {
};
Operation
.
byAccounts
=
async
function
byAccounts
(
accountNums
)
{
if
(
!
(
accountNums
instanceof
Array
))
if
(
!
(
accountNums
instanceof
Array
))
{
log
.
warn
(
'
Operation.byAccounts misuse: accountNums must be an array
'
);
}
let
params
=
{
keys
:
accountNums
...
...
@@ -75,10 +113,8 @@ Operation.byAccounts = async function byAccounts(accountNums) {
};
Operation
.
byBankSortedByDate
=
async
function
byBankSortedByDate
(
account
)
{
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
accountNumber
!==
'
string
'
)
{
log
.
warn
(
`Operation.byBankSortedByDate misuse: account must be an
Account`
);
if
(
typeof
account
!==
'
object
'
||
typeof
account
.
a