Compare commits
7 Commits
4a535d4080
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fc3c4787fe | |||
| 1035b3d0ab | |||
| 98c854929d | |||
| f5ec2f38fc | |||
| ba22833413 | |||
| 1365491c13 | |||
| 741762856d |
5
Gemfile
5
Gemfile
@@ -4,7 +4,4 @@ source 'https://rubygems.org'
|
||||
gem 'discordrb', git: 'https://github.com/shardlab/discordrb.git', branch: 'main'
|
||||
gem 'dotenv'
|
||||
gem 'pg'
|
||||
gem 'prawn'
|
||||
gem 'prawn-table'
|
||||
gem 'gruff'
|
||||
gem 'rmagick'
|
||||
gem 'i18n'
|
||||
42
Gemfile.lock
42
Gemfile.lock
@@ -17,7 +17,7 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
base64 (0.3.0)
|
||||
bigdecimal (3.3.1)
|
||||
concurrent-ruby (1.3.6)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (3.2.0)
|
||||
event_emitter (0.2.6)
|
||||
@@ -32,26 +32,20 @@ GEM
|
||||
ffi (1.17.3-x86_64-darwin)
|
||||
ffi (1.17.3-x86_64-linux-gnu)
|
||||
ffi (1.17.3-x86_64-linux-musl)
|
||||
gruff (0.29.0)
|
||||
bigdecimal (>= 3.0)
|
||||
histogram
|
||||
rmagick (>= 5.5)
|
||||
histogram (0.2.4.1)
|
||||
http-accept (1.7.0)
|
||||
http-cookie (1.1.0)
|
||||
domain_name (~> 0.5)
|
||||
i18n (1.14.8)
|
||||
concurrent-ruby (~> 1.0)
|
||||
logger (1.7.0)
|
||||
matrix (0.4.3)
|
||||
mime-types (3.7.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
||||
mime-types-data (3.2025.0924)
|
||||
mutex_m (0.3.0)
|
||||
netrc (0.11.0)
|
||||
observer (0.1.2)
|
||||
opus-ruby (1.0.1)
|
||||
ffi
|
||||
pdf-core (0.10.0)
|
||||
pg (1.6.3)
|
||||
pg (1.6.3-aarch64-linux)
|
||||
pg (1.6.3-aarch64-linux-musl)
|
||||
@@ -59,23 +53,11 @@ GEM
|
||||
pg (1.6.3-x86_64-darwin)
|
||||
pg (1.6.3-x86_64-linux)
|
||||
pg (1.6.3-x86_64-linux-musl)
|
||||
pkg-config (1.6.5)
|
||||
prawn (2.5.0)
|
||||
matrix (~> 0.4)
|
||||
pdf-core (~> 0.10.0)
|
||||
ttfunk (~> 1.8)
|
||||
prawn-table (0.2.2)
|
||||
prawn (>= 1.3.0, < 3.0.0)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
rmagick (6.1.5)
|
||||
observer (~> 0.1)
|
||||
pkg-config (~> 1.4)
|
||||
ttfunk (1.8.0)
|
||||
bigdecimal (~> 3.1)
|
||||
websocket (1.2.11)
|
||||
websocket-client-simple (0.9.0)
|
||||
base64
|
||||
@@ -99,15 +81,12 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
discordrb!
|
||||
dotenv
|
||||
gruff
|
||||
i18n
|
||||
pg
|
||||
prawn
|
||||
prawn-table
|
||||
rmagick
|
||||
|
||||
CHECKSUMS
|
||||
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
||||
bigdecimal (3.3.1) sha256=eaa01e228be54c4f9f53bf3cc34fe3d5e845c31963e7fcc5bedb05a4e7d52218
|
||||
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
||||
discordrb (3.7.2)
|
||||
discordrb-webhooks (3.7.2)
|
||||
domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933
|
||||
@@ -124,19 +103,15 @@ CHECKSUMS
|
||||
ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5
|
||||
ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f
|
||||
ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56
|
||||
gruff (0.29.0) sha256=ab808cbf507abda7ffacd4ba5805a43c47ad0ec6aa2a7b125cf8a165110047a0
|
||||
histogram (0.2.4.1) sha256=9a6e379172b88ea842ab71700a535dd037185a4e17abcce742c7444679ae2abc
|
||||
http-accept (1.7.0) sha256=c626860682bfbb3b46462f8c39cd470fd7b0584f61b3cc9df5b2e9eb9972a126
|
||||
http-cookie (1.1.0) sha256=38a5e60d1527eebc396831b8c4b9455440509881219273a6c99943d29eadbb19
|
||||
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
|
||||
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||
matrix (0.4.3) sha256=a0d5ab7ddcc1973ff690ab361b67f359acbb16958d1dc072b8b956a286564c5b
|
||||
mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56
|
||||
mime-types-data (3.2025.0924) sha256=f276bca15e59f35767cbcf2bc10e023e9200b30bd6a572c1daf7f4cc24994728
|
||||
mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
|
||||
netrc (0.11.0) sha256=de1ce33da8c99ab1d97871726cba75151113f117146becbe45aa85cb3dabee3f
|
||||
observer (0.1.2) sha256=d8a3107131ba661138d748e7be3dbafc0d82e732fffba9fccb3d7829880950ac
|
||||
opus-ruby (1.0.1) sha256=8dc808d6773a488469374cccf252808b2ad7bc7e00229a319832f0e09012ce53
|
||||
pdf-core (0.10.0) sha256=0a5d101e2063c01e3f941e1ee47cbb97f1adfc1395b58372f4f65f1300f3ce91
|
||||
pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99
|
||||
pg (1.6.3-aarch64-linux) sha256=0698ad563e02383c27510b76bf7d4cd2de19cd1d16a5013f375dd473e4be72ea
|
||||
pg (1.6.3-aarch64-linux-musl) sha256=06a75f4ea04b05140146f2a10550b8e0d9f006a79cdaf8b5b130cde40e3ecc2c
|
||||
@@ -144,12 +119,7 @@ CHECKSUMS
|
||||
pg (1.6.3-x86_64-darwin) sha256=ee2e04a17c0627225054ffeb43e31a95be9d7e93abda2737ea3ce4a62f2729d6
|
||||
pg (1.6.3-x86_64-linux) sha256=5d9e188c8f7a0295d162b7b88a768d8452a899977d44f3274d1946d67920ae8d
|
||||
pg (1.6.3-x86_64-linux-musl) sha256=9c9c90d98c72f78eb04c0f55e9618fe55d1512128e411035fe229ff427864009
|
||||
pkg-config (1.6.5) sha256=33f9f81c5322983d22b439b8b672f27777b406fea23bfec74ff14bbeb42ec733
|
||||
prawn (2.5.0) sha256=f4e20e3b4f30bf5b9ae37dad15eb421831594553aa930b2391b0fa0a99c43cb6
|
||||
prawn-table (0.2.2) sha256=336d46e39e003f77bf973337a958af6a68300b941c85cb22288872dc2b36addb
|
||||
rest-client (2.1.0) sha256=35a6400bdb14fae28596618e312776c158f7ebbb0ccad752ff4fa142bf2747e3
|
||||
rmagick (6.1.5) sha256=91c1734cc0effc3b1be18e6705ea0353d73cb492547002f542763fa08445acd1
|
||||
ttfunk (1.8.0) sha256=a7cbc7e489cc46e979dde04d34b5b9e4f5c8f1ee5fc6b1a7be39b829919d20ca
|
||||
websocket (1.2.11) sha256=b7e7a74e2410b5e85c25858b26b3322f29161e300935f70a0e0d3c35e0462737
|
||||
websocket-client-simple (0.9.0) sha256=f9a37c5e4922b35a711e21e6d73ed1e25892efa47d183203ab2f5beb4e563109
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Frugality is a Discord Bot written in Ruby using `discordrb` and PostgreSQL. Its
|
||||
1. Commands are separated into individual files in `src/commands`. This is the only place you'll need to add a new command.
|
||||
2. Automatically loads and registers new command files on startup.
|
||||
3. Uses PostgreSQL to store data (User IDs, coins amount, reason, timestamps).
|
||||
4. Supports Discord's slash commands.
|
||||
4. Supports Discord's slash commands, and embeds for financial reports.
|
||||
|
||||
## Prerequisites
|
||||
Before running the bot, ensure you have the following installed on your system:
|
||||
@@ -14,7 +14,6 @@ Before running the bot, ensure you have the following installed on your system:
|
||||
* **Bundler**
|
||||
* **PostgreSQL**
|
||||
* **Git**
|
||||
* **ImageMagick**
|
||||
|
||||
## Installation
|
||||
1. **Clone the repository:**
|
||||
@@ -62,7 +61,7 @@ The bot requires a PostgreSQL database.
|
||||
BOT_TOKEN=your_discord_bot_token_here
|
||||
TEST_SERVER_ID=your_discord_server_id
|
||||
```
|
||||
*Note: Add a Server ID only if you're planning on updating the bot frequently, and want instant changes.*
|
||||
*Note: Add a Server ID only if you're planning on updating the bot frequently, and want instant changes to be seen. Otherwise, remove it from the .env file and every `server_id: ENV['TEST_SERVER_ID']` line from the `register_application_command` on every `src/commands/*.rb` file.*
|
||||
|
||||
## Usage
|
||||
To start the bot, you must use `bundle exec` to load the local dependencies:
|
||||
|
||||
53
src/bot.rb
53
src/bot.rb
@@ -15,10 +15,22 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
require 'discordrb'
|
||||
require 'i18n'
|
||||
require_relative 'database'
|
||||
require_relative 'utils/locales_helper'
|
||||
|
||||
class FrugalityBot
|
||||
def initialize
|
||||
|
||||
I18n.config.enforce_available_locales = false
|
||||
|
||||
locales_path = File.join(File.dirname(__dir__), 'locales')
|
||||
I18n.load_path += Dir["#{locales_path}/*.yml"]
|
||||
|
||||
I18n.backend.load_translations
|
||||
I18n.default_locale = :en
|
||||
|
||||
|
||||
@bot = Discordrb::Bot.new(
|
||||
token: ENV['BOT_TOKEN'],
|
||||
intents: [:servers, :server_messages]
|
||||
@@ -27,7 +39,7 @@ class FrugalityBot
|
||||
@db = Database.new
|
||||
|
||||
load_commands
|
||||
setup_events
|
||||
startup_bot
|
||||
end
|
||||
|
||||
def run
|
||||
@@ -37,35 +49,22 @@ class FrugalityBot
|
||||
private
|
||||
|
||||
def load_commands
|
||||
# 1. We look for all .rb files in "src/commands/..."
|
||||
comm_files = Dir[File.join(__dir__, 'commands', '*.rb')]
|
||||
|
||||
comm_files.each do |file|
|
||||
require file # We import the file
|
||||
|
||||
# We convert filename to module name
|
||||
# This mean that 'echo.rb' turns into 'Echo'
|
||||
# 'server_info' would turn into 'ServerInfo'
|
||||
filename = File.basename(file, '.rb')
|
||||
module_name = filename.split('_').map(&:capitalize).join
|
||||
|
||||
begin
|
||||
# We find the module inside 'Commands' namespace
|
||||
comm_module = Commands.const_get(module_name)
|
||||
|
||||
# Register the command
|
||||
comm_module.register(@bot, @db)
|
||||
puts "Loaded command: #{module_name}"
|
||||
rescue NameError => e
|
||||
puts "Could not load #{filename}: Module 'Commands::#{module_name}' was not found."
|
||||
rescue StandardError => e
|
||||
puts "Error loading: #{filename}: #{e.message}"
|
||||
end
|
||||
Dir["#{File.dirname(__FILE__)}/commands/**/*.rb"].each do |file|
|
||||
require file
|
||||
end
|
||||
|
||||
Commands.constants.each do |const|
|
||||
cmd = Commands.const_get(const)
|
||||
|
||||
if cmd.is_a?(Module) && cmd.respond_to?(:register)
|
||||
cmd.register(@bot, @db)
|
||||
puts "Loaded command: #{const}"
|
||||
sleep(1.5)
|
||||
end
|
||||
end
|
||||
puts "Commands loaded."
|
||||
end
|
||||
|
||||
def setup_events
|
||||
def startup_bot
|
||||
@bot.ready do
|
||||
puts "#{@bot.profile.username} is online"
|
||||
@bot.update_status("online", "Checking the economy...", nil, 0, false, 0)
|
||||
|
||||
@@ -14,25 +14,40 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
require 'i18n'
|
||||
|
||||
module Commands
|
||||
module Add
|
||||
extend self
|
||||
module Add
|
||||
extend self
|
||||
|
||||
def register(bot, db)
|
||||
command_key = :add
|
||||
arg_amount_key = :amount
|
||||
arg_reason_key = :reason
|
||||
|
||||
cmd_desc = I18n.t('commands.add.description', locale: :en)
|
||||
amount_desc = I18n.t('commands.add.args.amount_desc', locale: :en)
|
||||
reason_desc = I18n.t('commands.add.args.reason_desc', locale: :en)
|
||||
|
||||
bot.register_application_command(command_key, cmd_desc, server_id: ENV['TEST_SERVER_ID']) do |cmd|
|
||||
cmd.integer(arg_amount_key, amount_desc, required: true)
|
||||
cmd.string(arg_reason_key, reason_desc, required: false)
|
||||
end
|
||||
|
||||
bot.application_command(command_key) do |event|
|
||||
db_lang = db.get_language(event.user.id)
|
||||
discord_lang = event.locale.to_s[0..1]
|
||||
I18n.locale = db_lang || (I18n.available_locales.include?(discord_lang.to_sym) ? discord_lang : :en)
|
||||
|
||||
user_id = event.user.id
|
||||
amount = event.options['amount']
|
||||
reason = event.options['reason'] || 'income'
|
||||
|
||||
def register(bot, db)
|
||||
bot.register_application_command(:add, 'Adds money to the wallet.', server_id: ENV['TEST_SERVER_ID']) do |cmd|
|
||||
cmd.integer('amount', 'The amount you want to add.', required: true)
|
||||
cmd.string('reason', "Reason you're adding money to the wallet. Leave empty for default.", required: false)
|
||||
end
|
||||
db.update_balance(user_id, amount, reason)
|
||||
|
||||
bot.application_command(:add) do |event|
|
||||
user_id = event.user.id
|
||||
amount = event.options['amount']
|
||||
reason = event.options['reason'] ||= 'transaction'
|
||||
|
||||
db.update_balance(user_id, amount, reason)
|
||||
|
||||
event.respond(content: "Added: #{amount} to the wallet.\nReason: #{reason}")
|
||||
end
|
||||
end
|
||||
msg = I18n.t('responses.add.success', amount: amount, reason: reason, default: "Added #{amount} (Reason: #{reason})")
|
||||
event.respond(content: msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -15,13 +15,13 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
module Commands
|
||||
module Currency
|
||||
module Balance
|
||||
extend self
|
||||
|
||||
def register(bot, db)
|
||||
bot.register_application_command(:currency, 'Get your currency', server_id: ENV['TEST_SERVER_ID'])
|
||||
bot.register_application_command(:balance, 'Get your currency', server_id: ENV['TEST_SERVER_ID'])
|
||||
|
||||
bot.application_command(:currency) do |event|
|
||||
bot.application_command(:balance) do |event|
|
||||
# 1. Get the User ID from the event
|
||||
user_id = event.user.id
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
require 'prawn'
|
||||
require 'prawn/table'
|
||||
require 'gruff'
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
require 'json'
|
||||
|
||||
module Commands
|
||||
module Statement
|
||||
@@ -36,70 +36,52 @@ module Commands
|
||||
user_id = event.user.id
|
||||
period = event.options['period']
|
||||
|
||||
# For income we fetch the data as stats[:income]
|
||||
# For expenses we fetch the data as stats[:expenses]
|
||||
# For net income we fetch the data as stats[:net]
|
||||
stats = db.fetch_report(user_id, period)
|
||||
|
||||
# We generate a Graph
|
||||
g = Gruff::Pie.new
|
||||
g.title = "Report"
|
||||
g.theme = Gruff::Themes::PASTEL
|
||||
chart_config = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['Income', 'Expenses'],
|
||||
datasets: [{
|
||||
data: [stats[:income], stats[:expenses].abs],
|
||||
backgroundColor: ['#9AF5AA', '#F55D5D'],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
plugins: {
|
||||
doughnutlabel: {
|
||||
labels: [
|
||||
{ text: stats[:net].to_s, font: { size: 20}},
|
||||
{ text: 'Net', font: { size: 10 }}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We add data
|
||||
g.data('Income', stats[:income])
|
||||
g.data('Expenses', stats[:expenses].abs)
|
||||
encoded_config = URI.encode_www_form_component(chart_config.to_json)
|
||||
chart_url = "https://quickchart.io/chart?c=#{encoded_config}&w=500&h=300&bkg=rgb(255,255,255)"
|
||||
|
||||
# We save the graph temporarily
|
||||
chart_path = "/tmp/chart_#{user_id}.png"
|
||||
g.write(chart_path)
|
||||
color_generated = ("0x" + Random.bytes(3).unpack1('H*')).to_i(16)
|
||||
|
||||
embed_generated = {
|
||||
title: "Financial Statement",
|
||||
description: "Report generated for **#{event.user.name}** (#{period})",
|
||||
color: color_generated,
|
||||
fields: [
|
||||
{ name: "Income", value: "#{stats[:income]} coins", inline: true },
|
||||
{ name: "Expenses", value: "#{stats[:expenses].abs} coins", inline: true },
|
||||
{ name: "Net Change", value: "#{stats[:net]} coins", inline: false }
|
||||
],
|
||||
image: { url: chart_url },
|
||||
footer: { text: "By FrugalityBot with QuickChart." }
|
||||
}
|
||||
|
||||
# We generate a PDF
|
||||
pdf_path = "/tmp/statement_#{user_id}.pdf"
|
||||
|
||||
Prawn::Document.generate(pdf_path) do |pdf|
|
||||
pdf.font "Helvetica"
|
||||
|
||||
# This should be the Header
|
||||
pdf.text "#{event.user.name}'s Financial Statement", size: 24, style: :bold, align: :center
|
||||
pdf.move_down 10
|
||||
pdf.text "Period: #{period}", align: :center
|
||||
pdf.move_down 20
|
||||
|
||||
# Summary table goes here
|
||||
data = [
|
||||
["Category", "$$$"],
|
||||
["Total Income", "#{stats[:income]} coins"],
|
||||
["Total Expenses", "#{stats[:expenses].abs} coins"],
|
||||
["Net Change", "#{stats[:net]} coins"]
|
||||
]
|
||||
|
||||
pdf.table(data, position: :center) do
|
||||
row(0).font_style = :bold
|
||||
row(0).background_color = "CCCCCC"
|
||||
self.header = true
|
||||
self.width = 400
|
||||
end
|
||||
|
||||
pdf.move_down 30
|
||||
|
||||
pdf.text "Visual Breakdown:", style: :bold
|
||||
pdf.move_down 10
|
||||
# We embed the image chart
|
||||
pdf.image chart_path, width: 400, position: :center
|
||||
|
||||
# Footer
|
||||
pdf.move_down 10
|
||||
pdf.text "Generated by Frugality using Gruff and Prawn", size: 10, align: :center, color: "888888"
|
||||
end
|
||||
|
||||
event.edit_response(content: "Report generated. Sending...")
|
||||
|
||||
# Send the report to the user
|
||||
File.open(pdf_path, 'r') do |f|
|
||||
event.channel.send_file(f, caption: "Here's your report.")
|
||||
end
|
||||
|
||||
# Cleanup
|
||||
File.delete(chart_path) if File.exist?(chart_path)
|
||||
File.delete(pdf_path) if File.exist?(pdf_path)
|
||||
event.edit_response(embeds: [embed_generated])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
45
src/commands/testing/embed.rb
Normal file
45
src/commands/testing/embed.rb
Normal file
@@ -0,0 +1,45 @@
|
||||
# FrugalityBot
|
||||
# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
require 'securerandom'
|
||||
|
||||
module Commands
|
||||
module Embed
|
||||
extend self
|
||||
|
||||
def register(bot, _db)
|
||||
bot.register_application_command(:embed, 'This is an embed testing', server_id: ENV['TEST_SERVER_ID']) do |cmd|
|
||||
end
|
||||
|
||||
bot.application_command(:embed) do |event|
|
||||
color_generated = ("0x" + Random.bytes(3).unpack1('H*')).to_i(16)
|
||||
embed_generated = {
|
||||
title: "Title testing.",
|
||||
description: "Description testing.",
|
||||
color: color_generated,
|
||||
fields: [
|
||||
{ name: "Field 1", value: "Value for field 1", inline: true },
|
||||
{ name: "Field 2", value: "Value for field 2", inline: false }
|
||||
],
|
||||
image: { url: "https://i.kym-cdn.com/photos/images/original/002/349/700/e38.jpg" },
|
||||
footer: { text: "Footer testing." }
|
||||
}
|
||||
|
||||
event.respond(embeds: [embed_generated])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -50,19 +50,23 @@ class Database
|
||||
@conn.exec(sql_wallet)
|
||||
@conn.exec(sql_ledger)
|
||||
@conn.exec(sql_index)
|
||||
|
||||
begin
|
||||
@conn.exec("ALTER TABLE wallets ADD COLUMN IF NOT EXISTS locale VARCHAR(5) DEFAULT 'en'")
|
||||
rescue PG::Error => e
|
||||
puts "Migration note: #{e.message}"
|
||||
end
|
||||
|
||||
puts "Database tables have been initialized."
|
||||
end
|
||||
|
||||
# We pass the user_id
|
||||
def get_currency(user_id)
|
||||
# 1. Run the query using parameters ($1) to prevent SQL injection
|
||||
# Run the query using parameters ($1) to prevent SQL injection
|
||||
result = @conn.exec_params("SELECT amount FROM wallets WHERE user_id = $1", [user_id])
|
||||
|
||||
# 2. Check if the user exists
|
||||
if result.num_tuples.zero?
|
||||
return 0 # User has no money/row yet
|
||||
else
|
||||
# 3. Return the value (don't print it)
|
||||
return result[0]['amount'].to_i
|
||||
end
|
||||
end
|
||||
@@ -106,4 +110,23 @@ class Database
|
||||
net: row['net_change'].to_i
|
||||
}
|
||||
end
|
||||
|
||||
def get_language(user_id)
|
||||
result = @conn.exec("SELECT locale FROM wallets WHERE user_id = $1", [user_id])
|
||||
|
||||
return nil if result.num_tuples.zero?
|
||||
|
||||
return result[0]['locale']
|
||||
end
|
||||
|
||||
def set_language(user_id, locale)
|
||||
sql = <<~SQL
|
||||
INSERT INTO wallets(user_id, amount, locale)
|
||||
VALUES ($1, 0, $2)
|
||||
ON CONFLICT (user_id)
|
||||
DO UPDATE SET locale = $2
|
||||
SQL
|
||||
|
||||
@conn.exec(sql, [user_id, locale])
|
||||
end
|
||||
end
|
||||
19
src/locales/en.yml
Normal file
19
src/locales/en.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
en:
|
||||
commands:
|
||||
add:
|
||||
name: "add"
|
||||
description: "Add money to the wallet."
|
||||
args:
|
||||
amount: "amount"
|
||||
amount_desc: "How much money you're adding to the wallet."
|
||||
reason: "reason"
|
||||
reason_desc: "Reason you're adding money. Leave blank for deafult."
|
||||
balance:
|
||||
name: "balance"
|
||||
description: "Check your wallet."
|
||||
|
||||
responses:
|
||||
add:
|
||||
success: "Added **%{amount}** coins to the wallet. Reason: **%{reason}**"
|
||||
balance:
|
||||
view: "You have **%{balance}** coins."
|
||||
19
src/locales/es.yml
Normal file
19
src/locales/es.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
es:
|
||||
commands:
|
||||
add:
|
||||
name: "añadir"
|
||||
description: "Añade monedas a la billetera."
|
||||
args:
|
||||
amount: "cantidad"
|
||||
amount_desc: "La cantidad de monedas que añades."
|
||||
reason: "motivo"
|
||||
reason_desc: "El motivo por el cual añades monedas. Déjalo vacío para default."
|
||||
balance:
|
||||
name: "saldo"
|
||||
description: "Revisa tu billetera."
|
||||
|
||||
responses:
|
||||
add:
|
||||
success: "Se añadieron **%{amount}** monedas a la billetera. Motivo: **%{reason}**"
|
||||
balance:
|
||||
view: "Tienes **%{balance}** monedas."
|
||||
41
src/utils/locales_helper.rb
Normal file
41
src/utils/locales_helper.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
# FrugalityBot
|
||||
# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
require 'i18n'
|
||||
|
||||
module LocalesHelper
|
||||
def self.generate(key_path)
|
||||
locales_map = {}
|
||||
|
||||
discord_map = {
|
||||
:en => 'en-US',
|
||||
:es => 'es-ES'
|
||||
}
|
||||
|
||||
I18n.available_locales.each do |lang|
|
||||
next if lang == :en
|
||||
|
||||
text = I18n.t(key_path, locale: lang, default: nil)
|
||||
|
||||
if text && text != 'nil'
|
||||
discord_code = discord_map[lang] || lang.to_s
|
||||
locales_map[discord_code] = text
|
||||
end
|
||||
end
|
||||
|
||||
return locales_map
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user