Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
17 changes: 17 additions & 0 deletions bot/database_service/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from firebase_admin import firestore
import firebase_admin
from firebase_admin import credentials
import os
import json


def get_db_client():
"""
Get credentials for the Google Sheets API.
"""
firebase_json = json.loads(os.environ["FIREBASE_JSON"])

cred = credentials.Certificate(firebase_json)
firebase_admin.initialize_app(cred)

return firestore.client()
44 changes: 44 additions & 0 deletions bot/database_service/firestore_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from bot.database_service.auth import get_db_client


class FirestoreService:
"""
This class is responsible for managing the Firestore database.
"""

def __init__(self):
self.db = get_db_client()

# New user setup
def new_user_setup(self, telegram_id, sheet_id):
user_ref = self.db.collection("users").document(str(telegram_id))
user_ref.set({"sheet_id": sheet_id})

# Check if user exists
def check_if_user_exists(self, telegram_id):
user_ref = self.db.collection("users").document(str(telegram_id))
user_doc = user_ref.get()
return user_doc.exists

# Get user sheet id
def get_user_sheet_id(self, telegram_id):
user_ref = self.db.collection("users").document(str(telegram_id))
user_doc = user_ref.get()
if user_doc.exists:
return user_doc.get("sheet_id")
else:
return None

# Get all user IDs
def get_all_user_id(self):
users_ref = self.db.collection("users")
user_ids = [int(user.id) for user in users_ref.stream()]
return user_ids

# Get all sheet IDs
def get_all_sheet_id(self):
users_ref = self.db.collection("users")
sheet_ids = []
for user in users_ref.stream():
sheet_ids.append(user.get("sheet_id"))
return sheet_ids
Empty file added bot/sheet_service/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions bot/sheet_service/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
auth.py

This file contains a function that returns the credentials for the Google Sheets API.
The credentials are obtained from the GOOGLE_JSON environment variable, which is set in the .env file.
The get_credentials function uses the google.oauth2.service_account module to create a credentials
object from the service account info in the GOOGLE_JSON environment variable.
The credentials object is then returned to the caller.

"""

import os
import json
from google.oauth2 import service_account


def get_credentials():
"""
Get credentials for the Google Sheets API.
"""
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
google_json = os.getenv("GOOGLE_JSON")
google_service = json.loads(google_json)
creds = service_account.Credentials.from_service_account_info(
google_service, scopes=SCOPES
)
return creds
58 changes: 58 additions & 0 deletions bot/sheet_service/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from googleapiclient.errors import HttpError
from functools import wraps

# Custom exception classes defined here


def google_sheets_exception_handler(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except HttpError as e:
if e.resp.status == 401:
raise AuthenticationError(
"Authentication failed: Check your credentials."
)
elif e.resp.status == 404:
raise SpreadsheetNotFoundError(
"Spreadsheet not found: Check your spreadsheet ID."
)
else:
raise APIRequestError(
f"API request failed with status {e.resp.status}: {e.error_details}"
)
except Exception as e:
raise SheetsServiceError(f"An unexpected error occurred: {str(e)}")

return wrapper


class SheetsServiceError(Exception):
"""Base class for exceptions in this module."""

pass


class AuthenticationError(SheetsServiceError):
"""Raised when there's an issue with authentication or credentials."""

pass


class SpreadsheetNotFoundError(SheetsServiceError):
"""Raised when a specified spreadsheet cannot be found."""

pass


class APIRequestError(SheetsServiceError):
"""Raised for errors related to making API requests to Google Sheets."""

pass


class InvalidEntryTypeError(SheetsServiceError):
"""Raised when an invalid entry type is specified."""

pass
115 changes: 115 additions & 0 deletions bot/sheet_service/sheets_range.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""
sheets_range.py

This file contains the ranges for the Google Sheets Services for consistency.
The ranges are used to access specific cells in the Google Sheets.

"""

from bot.google_sheet_service.utils import create_range, create_complex_range

# Sheet names
DD_SHEET = "Dropdown" # DD for Dropdown
TR_SHEET = "Tracker" # TR for Tracker

# Tracker columns
TR_QUICKADD_TP_PAY = "G" # Transport Payment Column
TR_QUICKADD_TP_TYPE = "H" # Transport Type Column
TR_QUICKADD_OT_PAY = "I" # Others Payment Column
TR_QUICKADD_OT_TYPE = "J" # Others Type Column

TR_QUICKADD_ROW_START = 3 # Quick Add Row
TR_QUICKADD_ROW_END = 13 # Quick Add End Row

TR_START_COL = "B" # Start Column
TR_END_COL = "E" # End Column
TR_ROW = 3

# Dropdown rows
DD_MAIN_CAT_ROW = 2
DD_SUBCAT_START = 3
DD_SUBCAT_END = 9

DD_MAIN_PAY_ROW = 12
DD_SUBPAY_START = 13
DD_SUBPAY_END = 19

DD_TRANSPORT_COL = "A"
DD_OTHERS_COL_START = "B"
DD_OTHERS_COL_END = "J"

DD_INCOME_COL = "L"

DD_PAYMENT_COL_START = "A"
DD_PAYMENT_COL_END = "J"

# Column indexes
START_COL_IDX = 0
END_COL_IDX = 11

# Months
OVERALL_RANGE = "!M13:O25"

# Transport ranges
TRANSPORT_RANGE = create_range(
DD_SHEET, DD_TRANSPORT_COL, DD_SUBCAT_START, DD_TRANSPORT_COL, DD_SUBCAT_END
)

# Others ranges
OTHERS_MAIN_RANGE = create_range(
DD_SHEET, DD_OTHERS_COL_START, DD_MAIN_CAT_ROW, DD_OTHERS_COL_END, DD_MAIN_CAT_ROW
)

OTHERS_SUB_RANGE = create_complex_range(
DD_SHEET,
ord(DD_OTHERS_COL_START),
ord(DD_OTHERS_COL_END),
DD_MAIN_CAT_ROW,
DD_SUBCAT_END,
)

# Payment ranges
PAYMENT_MAIN_RANGE = create_range(
DD_SHEET, DD_PAYMENT_COL_START, DD_MAIN_PAY_ROW, DD_PAYMENT_COL_END, DD_MAIN_PAY_ROW
)

PAYMENT_SUB_RANGE = create_complex_range(
DD_SHEET,
ord(DD_PAYMENT_COL_START),
ord(DD_PAYMENT_COL_END),
DD_MAIN_PAY_ROW,
DD_SUBPAY_END,
)

# Income range
INCOME_RANGE = create_range(
DD_SHEET, DD_INCOME_COL, DD_MAIN_CAT_ROW, DD_INCOME_COL, DD_SUBCAT_END
)

# Tracker ranges
TRACKER_RANGE = create_range(TR_SHEET, TR_START_COL, TR_ROW, TR_END_COL, TR_ROW)

# Quick add ranges
QUICK_ADD_RANGE = create_range(
TR_SHEET,
TR_QUICKADD_TP_PAY,
TR_QUICKADD_ROW_START,
TR_QUICKADD_OT_TYPE,
TR_QUICKADD_ROW_START,
)

QUICK_OTHERS_RANGE = create_range(
TR_SHEET,
TR_QUICKADD_OT_PAY,
TR_QUICKADD_ROW_START,
TR_QUICKADD_OT_TYPE,
TR_QUICKADD_ROW_END,
)

QUICK_TRANSPORT_RANGE = create_range(
TR_SHEET,
TR_QUICKADD_TP_PAY,
TR_QUICKADD_ROW_START,
TR_QUICKADD_TP_TYPE,
TR_QUICKADD_ROW_END,
)
Loading