mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 15:35:22 +02:00
Lint fixes, brakeman update
This commit is contained in:
parent
3490043a54
commit
07e37065d9
12 changed files with 309 additions and 286 deletions
|
@ -2,7 +2,7 @@ class FamilyExportsController < ApplicationController
|
||||||
include StreamExtensions
|
include StreamExtensions
|
||||||
|
|
||||||
before_action :require_admin
|
before_action :require_admin
|
||||||
before_action :set_export, only: [:download]
|
before_action :set_export, only: [ :download ]
|
||||||
|
|
||||||
def new
|
def new
|
||||||
# Modal view for initiating export
|
# Modal view for initiating export
|
||||||
|
@ -35,13 +35,13 @@ class FamilyExportsController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_export
|
def set_export
|
||||||
@export = Current.family.family_exports.find(params[:id])
|
@export = Current.family.family_exports.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_admin
|
def require_admin
|
||||||
unless Current.user.admin?
|
unless Current.user.admin?
|
||||||
redirect_to root_path, alert: "Access denied"
|
redirect_to root_path, alert: "Access denied"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
require 'zip'
|
require "zip"
|
||||||
require 'csv'
|
require "csv"
|
||||||
|
|
||||||
class Family::DataExporter
|
class Family::DataExporter
|
||||||
def initialize(family)
|
def initialize(family)
|
||||||
|
@ -37,202 +37,202 @@ class Family::DataExporter
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def generate_accounts_csv
|
def generate_accounts_csv
|
||||||
CSV.generate do |csv|
|
CSV.generate do |csv|
|
||||||
csv << ["id", "name", "type", "subtype", "balance", "currency", "created_at"]
|
csv << [ "id", "name", "type", "subtype", "balance", "currency", "created_at" ]
|
||||||
|
|
||||||
# Only export accounts belonging to this family
|
# Only export accounts belonging to this family
|
||||||
|
@family.accounts.includes(:accountable).find_each do |account|
|
||||||
|
csv << [
|
||||||
|
account.id,
|
||||||
|
account.name,
|
||||||
|
account.accountable_type,
|
||||||
|
account.subtype,
|
||||||
|
account.balance.to_s,
|
||||||
|
account.currency,
|
||||||
|
account.created_at.iso8601
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_transactions_csv
|
||||||
|
CSV.generate do |csv|
|
||||||
|
csv << [ "date", "account_name", "amount", "name", "category", "tags", "notes", "currency" ]
|
||||||
|
|
||||||
|
# Only export transactions from accounts belonging to this family
|
||||||
|
@family.transactions
|
||||||
|
.includes(:category, :tags, entry: :account)
|
||||||
|
.find_each do |transaction|
|
||||||
|
csv << [
|
||||||
|
transaction.entry.date.iso8601,
|
||||||
|
transaction.entry.account.name,
|
||||||
|
transaction.entry.amount.to_s,
|
||||||
|
transaction.entry.name,
|
||||||
|
transaction.category&.name,
|
||||||
|
transaction.tags.pluck(:name).join(","),
|
||||||
|
transaction.entry.notes,
|
||||||
|
transaction.entry.currency
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_trades_csv
|
||||||
|
CSV.generate do |csv|
|
||||||
|
csv << [ "date", "account_name", "ticker", "quantity", "price", "amount", "currency" ]
|
||||||
|
|
||||||
|
# Only export trades from accounts belonging to this family
|
||||||
|
@family.trades
|
||||||
|
.includes(:security, entry: :account)
|
||||||
|
.find_each do |trade|
|
||||||
|
csv << [
|
||||||
|
trade.entry.date.iso8601,
|
||||||
|
trade.entry.account.name,
|
||||||
|
trade.security.ticker,
|
||||||
|
trade.qty.to_s,
|
||||||
|
trade.price.to_s,
|
||||||
|
trade.entry.amount.to_s,
|
||||||
|
trade.currency
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_categories_csv
|
||||||
|
CSV.generate do |csv|
|
||||||
|
csv << [ "name", "color", "parent_category", "classification" ]
|
||||||
|
|
||||||
|
# Only export categories belonging to this family
|
||||||
|
@family.categories.includes(:parent).find_each do |category|
|
||||||
|
csv << [
|
||||||
|
category.name,
|
||||||
|
category.color,
|
||||||
|
category.parent&.name,
|
||||||
|
category.classification
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_ndjson
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
# Export accounts with full accountable data
|
||||||
@family.accounts.includes(:accountable).find_each do |account|
|
@family.accounts.includes(:accountable).find_each do |account|
|
||||||
csv << [
|
lines << {
|
||||||
account.id,
|
type: "Account",
|
||||||
account.name,
|
data: account.as_json(
|
||||||
account.accountable_type,
|
include: {
|
||||||
account.subtype,
|
accountable: {}
|
||||||
account.balance.to_s,
|
}
|
||||||
account.currency,
|
)
|
||||||
account.created_at.iso8601
|
}.to_json
|
||||||
]
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_transactions_csv
|
# Export categories
|
||||||
CSV.generate do |csv|
|
@family.categories.find_each do |category|
|
||||||
csv << ["date", "account_name", "amount", "name", "category", "tags", "notes", "currency"]
|
lines << {
|
||||||
|
type: "Category",
|
||||||
# Only export transactions from accounts belonging to this family
|
data: category.as_json
|
||||||
@family.transactions
|
}.to_json
|
||||||
.includes(:category, :tags, entry: :account)
|
|
||||||
.find_each do |transaction|
|
|
||||||
csv << [
|
|
||||||
transaction.entry.date.iso8601,
|
|
||||||
transaction.entry.account.name,
|
|
||||||
transaction.entry.amount.to_s,
|
|
||||||
transaction.entry.name,
|
|
||||||
transaction.category&.name,
|
|
||||||
transaction.tags.pluck(:name).join(","),
|
|
||||||
transaction.entry.notes,
|
|
||||||
transaction.entry.currency
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_trades_csv
|
|
||||||
CSV.generate do |csv|
|
|
||||||
csv << ["date", "account_name", "ticker", "quantity", "price", "amount", "currency"]
|
|
||||||
|
|
||||||
# Only export trades from accounts belonging to this family
|
|
||||||
@family.trades
|
|
||||||
.includes(:security, entry: :account)
|
|
||||||
.find_each do |trade|
|
|
||||||
csv << [
|
|
||||||
trade.entry.date.iso8601,
|
|
||||||
trade.entry.account.name,
|
|
||||||
trade.security.ticker,
|
|
||||||
trade.qty.to_s,
|
|
||||||
trade.price.to_s,
|
|
||||||
trade.entry.amount.to_s,
|
|
||||||
trade.currency
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_categories_csv
|
|
||||||
CSV.generate do |csv|
|
|
||||||
csv << ["name", "color", "parent_category", "classification"]
|
|
||||||
|
|
||||||
# Only export categories belonging to this family
|
|
||||||
@family.categories.includes(:parent).find_each do |category|
|
|
||||||
csv << [
|
|
||||||
category.name,
|
|
||||||
category.color,
|
|
||||||
category.parent&.name,
|
|
||||||
category.classification
|
|
||||||
]
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_ndjson
|
# Export tags
|
||||||
lines = []
|
@family.tags.find_each do |tag|
|
||||||
|
lines << {
|
||||||
|
type: "Tag",
|
||||||
|
data: tag.as_json
|
||||||
|
}.to_json
|
||||||
|
end
|
||||||
|
|
||||||
# Export accounts with full accountable data
|
# Export merchants (only family merchants)
|
||||||
@family.accounts.includes(:accountable).find_each do |account|
|
@family.merchants.find_each do |merchant|
|
||||||
lines << {
|
lines << {
|
||||||
type: "Account",
|
type: "Merchant",
|
||||||
data: account.as_json(
|
data: merchant.as_json
|
||||||
include: {
|
}.to_json
|
||||||
accountable: {}
|
end
|
||||||
|
|
||||||
|
# Export transactions with full data
|
||||||
|
@family.transactions.includes(:category, :merchant, :tags, entry: :account).find_each do |transaction|
|
||||||
|
lines << {
|
||||||
|
type: "Transaction",
|
||||||
|
data: {
|
||||||
|
id: transaction.id,
|
||||||
|
entry_id: transaction.entry.id,
|
||||||
|
account_id: transaction.entry.account_id,
|
||||||
|
date: transaction.entry.date,
|
||||||
|
amount: transaction.entry.amount,
|
||||||
|
currency: transaction.entry.currency,
|
||||||
|
name: transaction.entry.name,
|
||||||
|
notes: transaction.entry.notes,
|
||||||
|
excluded: transaction.entry.excluded,
|
||||||
|
category_id: transaction.category_id,
|
||||||
|
merchant_id: transaction.merchant_id,
|
||||||
|
tag_ids: transaction.tag_ids,
|
||||||
|
kind: transaction.kind,
|
||||||
|
created_at: transaction.created_at,
|
||||||
|
updated_at: transaction.updated_at
|
||||||
}
|
}
|
||||||
)
|
}.to_json
|
||||||
}.to_json
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# Export categories
|
# Export trades with full data
|
||||||
@family.categories.find_each do |category|
|
@family.trades.includes(:security, entry: :account).find_each do |trade|
|
||||||
lines << {
|
lines << {
|
||||||
type: "Category",
|
type: "Trade",
|
||||||
data: category.as_json
|
data: {
|
||||||
}.to_json
|
id: trade.id,
|
||||||
end
|
entry_id: trade.entry.id,
|
||||||
|
account_id: trade.entry.account_id,
|
||||||
|
security_id: trade.security_id,
|
||||||
|
ticker: trade.security.ticker,
|
||||||
|
date: trade.entry.date,
|
||||||
|
qty: trade.qty,
|
||||||
|
price: trade.price,
|
||||||
|
amount: trade.entry.amount,
|
||||||
|
currency: trade.currency,
|
||||||
|
created_at: trade.created_at,
|
||||||
|
updated_at: trade.updated_at
|
||||||
|
}
|
||||||
|
}.to_json
|
||||||
|
end
|
||||||
|
|
||||||
# Export tags
|
# Export valuations
|
||||||
@family.tags.find_each do |tag|
|
@family.entries.valuations.includes(:account, :entryable).find_each do |entry|
|
||||||
lines << {
|
lines << {
|
||||||
type: "Tag",
|
type: "Valuation",
|
||||||
data: tag.as_json
|
data: {
|
||||||
}.to_json
|
id: entry.entryable.id,
|
||||||
end
|
entry_id: entry.id,
|
||||||
|
account_id: entry.account_id,
|
||||||
|
date: entry.date,
|
||||||
|
amount: entry.amount,
|
||||||
|
currency: entry.currency,
|
||||||
|
name: entry.name,
|
||||||
|
created_at: entry.created_at,
|
||||||
|
updated_at: entry.updated_at
|
||||||
|
}
|
||||||
|
}.to_json
|
||||||
|
end
|
||||||
|
|
||||||
# Export merchants (only family merchants)
|
# Export budgets
|
||||||
@family.merchants.find_each do |merchant|
|
@family.budgets.find_each do |budget|
|
||||||
lines << {
|
lines << {
|
||||||
type: "Merchant",
|
type: "Budget",
|
||||||
data: merchant.as_json
|
data: budget.as_json
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
# Export transactions with full data
|
# Export budget categories
|
||||||
@family.transactions.includes(:category, :merchant, :tags, entry: :account).find_each do |transaction|
|
@family.budget_categories.includes(:budget, :category).find_each do |budget_category|
|
||||||
lines << {
|
lines << {
|
||||||
type: "Transaction",
|
type: "BudgetCategory",
|
||||||
data: {
|
data: budget_category.as_json
|
||||||
id: transaction.id,
|
}.to_json
|
||||||
entry_id: transaction.entry.id,
|
end
|
||||||
account_id: transaction.entry.account_id,
|
|
||||||
date: transaction.entry.date,
|
|
||||||
amount: transaction.entry.amount,
|
|
||||||
currency: transaction.entry.currency,
|
|
||||||
name: transaction.entry.name,
|
|
||||||
notes: transaction.entry.notes,
|
|
||||||
excluded: transaction.entry.excluded,
|
|
||||||
category_id: transaction.category_id,
|
|
||||||
merchant_id: transaction.merchant_id,
|
|
||||||
tag_ids: transaction.tag_ids,
|
|
||||||
kind: transaction.kind,
|
|
||||||
created_at: transaction.created_at,
|
|
||||||
updated_at: transaction.updated_at
|
|
||||||
}
|
|
||||||
}.to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# Export trades with full data
|
lines.join("\n")
|
||||||
@family.trades.includes(:security, entry: :account).find_each do |trade|
|
|
||||||
lines << {
|
|
||||||
type: "Trade",
|
|
||||||
data: {
|
|
||||||
id: trade.id,
|
|
||||||
entry_id: trade.entry.id,
|
|
||||||
account_id: trade.entry.account_id,
|
|
||||||
security_id: trade.security_id,
|
|
||||||
ticker: trade.security.ticker,
|
|
||||||
date: trade.entry.date,
|
|
||||||
qty: trade.qty,
|
|
||||||
price: trade.price,
|
|
||||||
amount: trade.entry.amount,
|
|
||||||
currency: trade.currency,
|
|
||||||
created_at: trade.created_at,
|
|
||||||
updated_at: trade.updated_at
|
|
||||||
}
|
|
||||||
}.to_json
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Export valuations
|
|
||||||
@family.entries.valuations.includes(:account, :entryable).find_each do |entry|
|
|
||||||
lines << {
|
|
||||||
type: "Valuation",
|
|
||||||
data: {
|
|
||||||
id: entry.entryable.id,
|
|
||||||
entry_id: entry.id,
|
|
||||||
account_id: entry.account_id,
|
|
||||||
date: entry.date,
|
|
||||||
amount: entry.amount,
|
|
||||||
currency: entry.currency,
|
|
||||||
name: entry.name,
|
|
||||||
created_at: entry.created_at,
|
|
||||||
updated_at: entry.updated_at
|
|
||||||
}
|
|
||||||
}.to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# Export budgets
|
|
||||||
@family.budgets.find_each do |budget|
|
|
||||||
lines << {
|
|
||||||
type: "Budget",
|
|
||||||
data: budget.as_json
|
|
||||||
}.to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# Export budget categories
|
|
||||||
@family.budget_categories.includes(:budget, :category).find_each do |budget_category|
|
|
||||||
lines << {
|
|
||||||
type: "BudgetCategory",
|
|
||||||
data: budget_category.as_json
|
|
||||||
}.to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
lines.join("\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,5 +1,28 @@
|
||||||
{
|
{
|
||||||
"ignored_warnings": [
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"warning_type": "Redirect",
|
||||||
|
"warning_code": 18,
|
||||||
|
"fingerprint": "723b1970ca6bf16ea0c2c1afa0c00d3c54854a16568d6cb933e497947565d9ab",
|
||||||
|
"check_name": "Redirect",
|
||||||
|
"message": "Possible unprotected redirect",
|
||||||
|
"file": "app/controllers/family_exports_controller.rb",
|
||||||
|
"line": 30,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
||||||
|
"code": "redirect_to(Current.family.family_exports.find(params[:id]).export_file, :allow_other_host => true)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "FamilyExportsController",
|
||||||
|
"method": "download"
|
||||||
|
},
|
||||||
|
"user_input": "Current.family.family_exports.find(params[:id]).export_file",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"cwe_id": [
|
||||||
|
601
|
||||||
|
],
|
||||||
|
"note": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Mass Assignment",
|
"warning_type": "Mass Assignment",
|
||||||
"warning_code": 105,
|
"warning_code": 105,
|
||||||
|
@ -105,5 +128,5 @@
|
||||||
"note": ""
|
"note": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"brakeman_version": "7.0.2"
|
"brakeman_version": "7.1.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Family::DataExporterTest < ActiveSupport::TestCase
|
||||||
assert zip_data.is_a?(StringIO)
|
assert zip_data.is_a?(StringIO)
|
||||||
|
|
||||||
# Check that the zip contains all expected files
|
# Check that the zip contains all expected files
|
||||||
expected_files = ["accounts.csv", "transactions.csv", "trades.csv", "categories.csv", "all.ndjson"]
|
expected_files = [ "accounts.csv", "transactions.csv", "trades.csv", "categories.csv", "all.ndjson" ]
|
||||||
|
|
||||||
Zip::File.open_buffer(zip_data) do |zip|
|
Zip::File.open_buffer(zip_data) do |zip|
|
||||||
actual_files = zip.entries.map(&:name)
|
actual_files = zip.entries.map(&:name)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue