Compare commits

...
Sign in to create a new pull request.

8 commits
main ... dev

Author SHA1 Message Date
MrEisbear
af3f02341e feat: Update README and implement Discord user registration endpoints 2025-09-24 19:42:46 -05:00
MrEisbear
e09463b59c feat: Add Discord routes and configuration for bot key validation 2025-09-24 19:19:32 -05:00
MrEisbear
df2242ea44 Merge branch 'main' into dev-nontested to ignore todo 2025-09-20 21:17:55 -05:00
MrEisbear
7b95213914 updated to do 2025-09-20 21:16:25 -05:00
MrEisbear
132545f996 docs: Add request body details for transfer-business endpoint in README 2025-09-20 21:07:50 -05:00
MrEisbear
2987adad3e fix two routes being named equally 2025-09-20 21:04:30 -05:00
MrEisbear
dcee6058cb feat: Add transaction routes and update configurations
This commit introduces new transaction routes for handling various transaction-related operations. It also includes updates to the `config.py` file to support these new features.

The following files were modified:
- `README.md`: Updated documentation to clarify .env variables and their purposes
- `To-Do.md`: Updated task meaningless
- `config.py`: Added COLLECT_COOLDOWN and TAX_ACCOUNT_BID configurations.

    Main Thing:
- `interbend/routes/transaction_routes.py`:
Added boilerplate transaction to handle all transfers and separated business transfers with tax application.
/transfer for personal transfers
/transfer-business for business transfers with tax deduction

TODO: add route to change tax rate and add non hardcoded tax rate.
Type 6 and 7 are reserved for future use. currently implemented are 0 and 1.
2025-09-20 20:59:19 -05:00
MrEisbear
3c5550beed fix(admin): Correct variable name in add_money validation 2025-09-20 20:28:26 -05:00
9 changed files with 209 additions and 31 deletions

View file

@ -2,6 +2,9 @@
Interbend is a Flask-based web application that provides a backend API for managing user balances and transactions. It features a robust authentication system using JWT and includes a separate set of administrative endpoints for system management. The application is designed to be extensible and can be used as a foundation for a variety of financial applications.
### Note
The GitHub branch may lag behind the development branch. For the most up-to-date code and pull requests, please visit [https://git.albioncloud.de/Eisbear/Interbend](https://git.albioncloud.de/Eisbear/Interbend).
## Installation
1. **Clone the repository:**
@ -25,13 +28,14 @@ Interbend is a Flask-based web application that provides a backend API for manag
Create a `.env` file in the root directory of the project and add the following variables:
```
JWT_KEY=your_secret_jwt_key
JWT_EXPIRATION=30
JWT_EXPIRATION=30 // jwt experation duration in days
DB_HOST=your_database_host
DB_USER=your_database_user
DB_PASSWORD=your_database_password
DB_NAME=your_database_name
ADMIN_KEY=your_secret_admin_key
COLLECT_COOLDOWN=30
COLLECT_COOLDOWN=24 // collect cooldown in hours
TAX_ACCOUNT_BID=BUSINESS_BID_HERE // tax account bid here
```
## Usage
@ -68,6 +72,10 @@ The application will start in debug mode on `http://127.0.0.1:5000`.
- **Request Body**: `{ "to": "recipient_bid", "amount": 50.00, "note": "Payment for services" }`
- **Response**: A success message.
- **`POST /transfer-business`**: Transfers a specified amount from the authenticated user to another user with an appled tax.
- **Authentication**: JWT token required.
- **Request Body**: `{ "to": "recipient_bid", "amount": 50.00, "note": "Payment for services" }`
- **Response**: A success message.
### Admin
All admin endpoints require an admin key in the request body.
@ -83,3 +91,9 @@ All admin endpoints require an admin key in the request body.
- **`POST /admin/change-password`**: Changes the password for a user.
- **Request Body**: `{ "bid": "user_bid", "password": "new_password", "key": "your_admin_key" }`
- **Response**: A success message.
### Bot
All bot endpoints require a bot key in the request body. These endpoints are designed with the InterBot discordbot in mind.
You should never use these manually because they trust the discord bot for authentication and are therefore insecure.
(i dont think thats best practice?)
// TODO - Add Discord End Points here \/

View file

@ -4,14 +4,41 @@ This file tracks potential new features and improvements for the Interbend banki
## Feature Suggestions
1. **Automated Payroll System:**
* **Description:** Instead of requiring users to manually call the `/collect` endpoint, a scheduled script could run periodically (e.g., every 24 hours) to automatically distribute salaries to all eligible users.
* **Benefits:** Improves user experience, ensures consistent pay, and reduces repeated API calls to the server.
* **Important:** Due to the concept of this whole system it needs to be considered to only pay users who are attend. Bad Idea.
* **Alternative:** Implement system to make sure you can only collect if the host is online. Make admin route to open server (set global bool)
1. **Automated Payroll System**
* **Description:** Instead of requiring users to manually call the `/collect` endpoint, a scheduled script could run periodically to automatically distribute salaries to all eligible users.
* **Benefits:** Improves user experience, ensures consistent pay, and reduces repeated API calls to the server.
* **Status:** Under Review
* **Note:** Due to system concept, needs to be modified to only pay active users.
* **Alternative:** Implement system to verify host is online; add admin route to control server availability.
2. **User Transaction History:**
* **Description:** Create a new API endpoint (e.g., `GET /transactions`) that allows an authenticated user to retrieve a paginated list of their own transaction history.
* **Benefits:** Provides users with transparency and a way to track their finances, which is a core feature of any banking application.
2. **User Transaction History**
* **Description:** Create API endpoint for retrieving paginated transaction history.
* **Benefits:** Provides transparency and financial tracking for users.
* **Status:** COMPLETED
* **Note:** Needs verification testing.
* FINISHED: PLEASE CHECK IF WORKING!
3. **Changeable Tax Rate**
* **Description:** Add system for dynamic tax rate adjustment through admin interface.
* **Benefits:** Allows economic control and flexibility for different transaction types.
* **Status:** In Progress
* **Implementation:** Store in database for persistence, add admin routes for modification.
4. **User Roles System**
* **Description:** Implement comprehensive role-based access control (RBAC).
* **Benefits:** Enables different permissions for police, government, admin, and regular users.
* **Status:** Not Started
* **Required Features:**
- Role assignment and management
- Permission hierarchy
- Role-specific interfaces
- Audit logging for role changes
5. **Frontend Development**
* **Description:** Create user interface for the banking system.
* **Benefits:** Provides intuitive access to banking features.
* **Status:** Not Started
* **Components Needed:**
- User dashboard
- Transaction interface
- Admin control panel
- Role-specific views

View file

@ -9,6 +9,9 @@ class Config:
# General Config
JWT_KEY = os.getenv('JWT_KEY')
JWT_EXPIRE = int(os.getenv('JWT_EXPIRATION', 30))
# Gets the Key to ensure discord bot requests are being done by the discord bot
BOT_KEY = os.getenv('BOT_KEY')
# Database
DB_HOST = os.getenv('DB_HOST')
@ -19,3 +22,4 @@ class Config:
# Admin
ADMIN_KEY = os.getenv('ADMIN_KEY')
COLLECT_COOLDOWN = int(os.getenv('COLLECT_COOLDOWN', 24))
TAX_ACCOUNT_BID = os.getenv('TAX_ACCOUNT_BID')

View file

@ -8,8 +8,10 @@ def create_app(config_class=Config):
from .routes.auth_routes import auth_bp
from .routes.transaction_routes import transactions_bp
from .routes.admin_routes import admin_bp
from .routes.discord_routes import discord_bp
app.register_blueprint(auth_bp)
app.register_blueprint(transactions_bp)
app.register_blueprint(admin_bp, url_prefix='/admin')
app.register_blueprint(discord_bp, url_prefix='/discord')
return app

View file

@ -40,4 +40,18 @@ def token_gen(bid):
{"bid": bid, "exp": exptime},
jwt_key,
algorithm="HS256")
return token
return token
def botKey(input_key):
bot_key = current_app.config['BOT_KEY']
if input_key != bot_key:
return False
if input_key == bot_key: # Extra Security which doesnt actually add anything but peace of mind.
return True
return "OhShit" # This should never happen??
# I dont think I should be a programmer, I dont even understand python and prefer golang or java or C#. ANYTHING THAT HAS {}
def bot_key(input_key):
return botKey(input_key)
# Legacy, decaprecated (wait I didnt even implement this so why do I even keep this?)
# Random bloat :3

View file

@ -41,7 +41,7 @@ def add_money():
bid = data.get('bid')
amount = data.get('amount')
key = data.get('key')
if not bid or not money or not key:
if not bid or not amount or not key:
return jsonify({"error": "BID, Amount and AdminKey are required"}), 400
if not _keychecker(key):
return jsonify({"error":"Admin Key required"}), 403

View file

@ -0,0 +1,71 @@
from webbrowser import get
from flask import Blueprint, make_response
from interbend.db import db, get_user
from interbend.auth import *
import mysql.connector
import auth # For bot_key function
from werkzeug.security import generate_password_hash, check_password_hash
discord_bp = Blueprint('discord_bp', __name__)
@discord_bp.route('/register-id', methods=['POST'])
def register_id():
data = request.get_json()
bid = data.get('bid')
name = data.get('name')
origin = data.get('origin')
age = data.get('age')
gender = data.get('gender')
bot_key2 = data.get('bot_key')
if bot_key2 != current_app.config['BOT_KEY']:
return jsonify({"error": "Unauthorized"}), 401
if not bid or not name or not origin or not age or not gender:
return jsonify({"error": "BID, name, origin, age, and gender are required"}), 400
user = get_user(bid)
if not user:
return jsonify({"error": "User is not registered"}), 404
# Should the user be automatically registered here?
return jsonify({"error": "Method not implemented"}), 501
@discord_bp.route('/register-2', methods=['POST'])
def register2():
data = request.get_json()
bid = data.get('bid')
# Bid is now generated by API -- Not in this case because this is for the discord bot to register users
username = data.get('username')
email = data.get('email')
# This wont work because the bot wont have access to the email. Its a bot not OAuth, which will be added later.
password = data.get('password') # The bot will generate a random password and send it to the user via DM or something?
bot_key2 = data.get('bot_key')
if not botKey(bot_key2):
return jsonify({"error": "Unauthorized"}), 401
if not username or not password:
return jsonify({"error": "Bot error, did not supply username or password"}), 404
password_hash = generate_password_hash(password)
if email == "example@example.com":
return jsonify({"error": "bro"}), 400
bidf = "D-".join(bid)
try:
with db.cursor(dictionary=True) as cur:
cur.execute("SELECT * FROM users WHERE bid = %s", (bidf,))
if cur.fetchone():
return jsonify({"error": "BID already exists."}), 409
except mysql.connector.Error as err:
db.rollback()
current_app.logger.error(f"Database error in register: {err}")
return jsonify({"error": "Database Error"}), 500
try:
with db.cursor(dictionary=True) as cur:
cur.execute("INSERT INTO users (bid, username, password_hash) VALUES (%s, %s, %s)",
(bid, username, password_hash))
db.commit()
return jsonify({"message": "Creation Successful"}), 201
except mysql.connector.Error as err:
db.rollback()
current_app.logger.error(f"Database error in register: {err}")
return jsonify({"error": "Database Error"}), 500
@discord_bp.route('/balance', methods=['GET'])
def blo_chicken_tiki_masala(): #can I name it like this?
return jsonify({"error": "use normal balance bro"}), 404

View file

@ -94,23 +94,17 @@ def get_transactions():
return jsonify({"error": "An unexpected server error occurred."}), 500
# this should be fine
@transactions_bp.route('/transfer', methods=['POST'])
@jwt_required
def transfer():
# Ignore warning because it's dynamically added via jwt required.
user_bid = request.bid
data = request.get_json()
fbid = data.get('from')
tbid = data.get('to')
amount = data.get('amount')
note = data.get('note')
if not tbid or not amount:
return jsonify({"error": "To and amount are required"}), 400
if not fbid:
fbid = user_bid
if fbid != user_bid:
return jsonify({"error": "Unauthorized transfer from another account"}), 401
# this should be fine (not)
def transfer_boilerplate(user_bid, fbid, tbid, amount, note, type):
if not user_bid or not fbid or not tbid or not amount:
return jsonify({"error": "From, To, and amount are required"}), 400
if not note:
print(f"{type} failed to provide note. No trace available because I am lazy to program such things.")
return jsonify ({"error": "Note shouldve been passed by internal method."}), 500
if not type in [0, 1, 2, 3, 4, 5, 6, 7, 8]: # 0 = personal, 1 = business, 2 = fine, 3 = salary, 4 = bill, 5 = admin adjustment, 6 = placeholder, 7 = placeholder2, 8 = other
print(f"type was {type}, which is invalid. This is a bug. Internal Method failed to provide a valid type. No trace available because I am lazy to program such things.")
return jsonify({"error": "Internal method failed to provide a valid type."}), 500
try:
amount = float(amount)
if amount <= 0:
@ -121,6 +115,15 @@ def transfer():
receiver = get_user(tbid)
if not sender or not receiver:
return jsonify({"error":"User not found"}), 404
# here is space to add tax if its a business transaction.
if type == 1: # Business Transfer
gtax = 0.3 # 30% tax for business transactions - configurable later TO DO
tax = amount * gtax
note += f" (Tax applied: {tax})"
tax_account_bid = Config.TAX_ACCOUNT_BID
if sender["balance"] < amount + tax:
return jsonify({"error": "Insufficient funds"}), 400
if sender["balance"] < amount:
return jsonify({"error": "Insufficient funds"}), 400
try:
@ -128,6 +131,9 @@ def transfer():
with db.cursor(dictionary=True) as cur:
cur.execute("UPDATE users SET balance = balance - %s WHERE bid = %s", (amount, fbid))
cur.execute("UPDATE users SET balance = balance + %s WHERE bid = %s", (amount, tbid))
if type == 1: # Business Transfer
cur.execute("UPDATE users SET balance = balance - %s WHERE bid = %s", (tax, fbid))
cur.execute("UPDATE users SET balance = balance + %s WHERE bid = %s", (tax, tax_account_bid))
cur.execute("INSERT INTO transactions (source, target, amount, note, type, timestamp, status) VALUES (%s, %s, "
"%s, %s, %s, %s)", fbid, tbid, amount, note, "transfer", datetime.now(timezone.utc),
"completed", )
@ -136,4 +142,44 @@ def transfer():
except mysql.connector.Error as err:
db.rollback()
print(f"Transactional Error: {err}")
return jsonify({"error": "A database error occurred during the transfer."}), 500
return jsonify({"error": "A database error occurred during the transfer."}), 500
# PERSONAL TRANSFERS
@transactions_bp.route('/transfer', methods=['POST'])
@jwt_required
def transfer():
# Ignore warning because it's dynamically added via jwt required.
user_bid = request.bid
data = request.get_json()
fbid = data.get('from')
tbid = data.get('to')
amount = data.get('amount')
note = data.get('note')
type = int(0) # Personal Transfer
if not fbid:
user_bid = fbid
if fbid != user_bid:
return jsonify({"error": "Unauthorized transfer from another account"}), 401
if not note:
note = "No note provided, Personal Transfer from " + fbid
return transfer_boilerplate(user_bid, fbid, tbid, amount, note, type)
# BUSINESS TRANSFERS
@transactions_bp.route('/transfer-business', methods=['POST'])
@jwt_required
def transfer_business():
# Ignore warning because it's dynamically added via jwt required.
user_bid = request.bid
data = request.get_json()
fbid = data.get('from')
tbid = data.get('to')
amount = data.get('amount')
note = data.get('note')
type = int(1) # Business Transfer
if not fbid:
user_bid = fbid
if fbid != user_bid:
return jsonify({"error": "Unauthorized transfer from another account"}), 401
if not note:
note = "No note provided, Business Transfer from " + fbid
return transfer_boilerplate(user_bid, fbid, tbid, amount, note, type)