Skip to content

Commit

Permalink
Update Setup Instructions; Update Spreadsheet Service
Browse files Browse the repository at this point in the history
  • Loading branch information
s2t2 committed Jan 23, 2024
1 parent 8f0733a commit 84930a6
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 124 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Make a copy of this template repo (as necessary). Clone your copy of the repo on
Setup and activate a new Anaconda virtual environment:

```sh
conda create -n flask-sheets-env-2023 python=3.10
conda activate flask-sheets-env-2023
conda create -n gradebook-hero-env python=3.10
conda activate gradebook-hero-env
```

Install package dependencies:
Expand Down Expand Up @@ -87,25 +87,26 @@ GOOGLE_CLIENT_SECRET="____________"
#
# GOOGLE SHEETS DATABASE
#
GOOGLE_SHEETS_DOCUMENT_ID="____________"
#GOOGLE_SHEETS_DOCUMENT_ID="____________"

#
# GOOGLE ANALYTICS
#
GA_TRACKER_ID="UA-XXXXXXX-1"
#GA_TRACKER_ID="UA-XXXXXXX-1"
```





## Usage

### Sheets Service

After configuring the Google Sheet database and populating it with products, you should be able to test out the app's ability to fetch products (and generate new orders):

```sh
python -m app.sheets_service
python -m app.spreadsheet_service
```

### Web Application
Expand Down
123 changes: 4 additions & 119 deletions app/spreadsheet_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,12 @@


class SpreadsheetService:
# TODO: consider implementing a locking mechanism on sheet writes, to prevent overwriting (if it becomes an issue)
# ... however we know that if we want a more serious database solution, we would choose SQL database (and this app is just a small scale demo)

def __init__(self, credentials_filepath=GOOGLE_CREDENTIALS_FILEPATH, document_id=GOOGLE_SHEETS_DOCUMENT_ID):
print("INITIALIZING NEW SPREADSHEET SERVICE...")

#self.credentials = credentials or ServiceAccountCredentials.from_json_keyfile_name(CREDENTIALS_FILEPATH, AUTH_SCOPE)
#self.credentials = ServiceAccountCredentials._from_parsed_json_keyfile(json.loads(GOOGLE_API_CREDENTIALS), AUTH_SCOPE)
#self.client = gspread.authorize(self.credentials) #> <class 'gspread.client.Client'>
self.client = gspread.service_account(filename=credentials_filepath)

self.document_id = document_id

# TODO: consider storing and caching the latest version of each sheet, given the small number of sheets
# ... showing preference for speed over brevity
#self.products_sheet = None
#self.orders_sheet = None

@staticmethod
def generate_timestamp():
Expand All @@ -54,9 +43,6 @@ def parse_timestamp(ts:str):
date_format = "%Y-%m-%d %H:%M:%S.%f%z"
return datetime.strptime(ts, date_format)

# READING DATA
# ... TODO: consider passing the sheet or the sheet name, and getting the sheet only if necessary

@property
def doc(self):
"""note: this will make an API call each time, to get the new data"""
Expand Down Expand Up @@ -84,114 +70,13 @@ def destroy_all(self, sheet_name):
# ... to account for the header row
sheet.delete_rows(start_index=2, end_index=len(records)+1)

def get_products(self):
_, products = self.get_records("products")
return products

def get_orders(self):
_, orders = self.get_records("orders")
return records

def get_user_orders(self, user_email):
_, orders = self.get_records("orders")
return [order for order in orders if order["user_email"] == user_email]


# WRITING DATA

def seed_products(self):
sheet, products = self.get_records("products")
if not any(products):
DEFAULT_PRODUCTS = [
{'id': 1, 'name': 'Strawberries', 'description': 'Juicy organic strawberries.', 'price': 4.99, 'url': 'https://picsum.photos/id/1080/360/200'},
{'id': 2, 'name': 'Cup of Tea', 'description': 'An individually-prepared tea or coffee of choice.', 'price': 3.49, 'url': 'https://picsum.photos/id/225/360/200'},
{'id': 3, 'name': 'Textbook', 'description': 'It has all the answers.', 'price': 129.99, 'url': 'https://picsum.photos/id/24/360/200'}
]
self.create_products(DEFAULT_PRODUCTS)

def create_products(self, new_products:list):
self.create_records("products", new_products)

def create_product(self, new_product:dict):
self.create_records("products", [new_product])

def create_orders(self, new_orders:list):
self.create_records("orders", new_orders)

def create_order(self, new_order:dict):
self.create_records("orders", [new_order])



def create_records(self, sheet_name:str, new_records:list):
model_class = {"products": Product, "orders": Order}[sheet_name]

sheet, records = self.get_records(sheet_name)
next_row_number = len(records) + 2 # plus headers plus one

# auto-increment integer identifier
if any(records):
existing_ids = [r["id"] for r in records]
next_id = max(existing_ids) + 1
else:
next_id = 1

new_rows = []
for new_record in new_records:
new_record["id"] = next_id
new_record["created_at"] = self.generate_timestamp()
new_row = model_class(new_record).to_row
new_rows.append(new_row)

next_id += 1

sheet.insert_rows(new_rows, row=next_row_number)






# FIXED SCHEMA / DECORATORS
# ... to make sure when writing to sheet the values are in the proper order

class Product:
def __init__(self, attrs):
self.id = attrs.get("id")
self.name = attrs.get("name")
self.description = attrs.get("description")
self.price = attrs.get("price")
self.url = attrs.get("url")
self.created_at = attrs.get("created_at")

@property
def to_row(self):
return [self.id, self.name, self.description, self.price, self.url, str(self.created_at)]


class Order:
def __init__(self, attrs):
self.id = attrs.get("id")
self.user_email = attrs.get("user_email")
self.product_id = attrs.get("product_id")
self.product_name = attrs.get("product_name")
self.product_price = attrs.get("product_price")
self.created_at = attrs.get("created_at")


@property
def to_row(self):
return [self.id, self.user_email, self.product_id, self.product_name, self.product_price, str(self.created_at)]


if __name__ == "__main__":

ss = SpreadsheetService()

ss.seed_products()

sheet, records = ss.get_records("products")

for record in records:
print("-----")
pprint(record)
docs = ss.client.list_spreadsheet_files()
for doc in docs:
print(type(doc))
pprint(doc)

0 comments on commit 84930a6

Please sign in to comment.