From a1a6a8a7b8fa582ce437b4fdec8a758163561f22 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:18:33 +0200 Subject: [PATCH 01/10] Feat (ED-77): add credentials.json and token.json to gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 53af7d0b..d6a5a8b2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ Gemfile.lock assets/libs/ node_modules/ vendor -.idea \ No newline at end of file +.idea +scripts/credentials.json +scripts/token.json \ No newline at end of file From e5d8a54aea411e0e4822d27792e53cef342c21e0 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:21:04 +0200 Subject: [PATCH 02/10] Feat (ED-77): add script to parse Collections from spreadsheet into json --- scripts/collections_sheet_to_json.py | 61 ++++++++++++++++++++++++++++ scripts/modify_json.py | 40 ------------------ 2 files changed, 61 insertions(+), 40 deletions(-) create mode 100644 scripts/collections_sheet_to_json.py delete mode 100644 scripts/modify_json.py diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py new file mode 100644 index 00000000..68d67c3b --- /dev/null +++ b/scripts/collections_sheet_to_json.py @@ -0,0 +1,61 @@ +import os.path +import json + +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError + +SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] + +COLLECTIONS_DENES_SHEET_ID = "1q_ityTPJaBxxmANQawi4Kjamq5wIVoQkahLsp63rP7g" +RANGE = "Sheet1" + + +def main(): + credentials = None + if os.path.exists("token.json"): + credentials = Credentials.from_authorized_user_file("token.json", SCOPES) + if not credentials or not credentials.valid: + if credentials and credentials.expired and credentials.refresh_token: + credentials.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES) + credentials = flow.run_local_server(port=0) + with open("token.json", "w") as token: + token.write(credentials.to_json()) + + try: + service = build("sheets", "v4", credentials=credentials) + sheets = service.spreadsheets() + + result = sheets.values().get(spreadsheetId=COLLECTIONS_DENES_SHEET_ID, range=RANGE).execute() + + values = result.get("values", []) + + if not values: + print("No data found.") + return + + # Extract header + header = values[0] + data = [] + + # Transform rows into a list of dictionaries + for row in values[1:]: + row_data = {header[i]: row[i] if i < len(row) else "" for i in range(len(header))} + data.append(row_data) + + # Write data to collections.json file + with open("collections.json", "w", encoding='utf-8') as json_file: + json.dump(data, json_file, indent=4, ensure_ascii=False) + + print("Data has been written to collections.json") + + except HttpError as error: + print(error) + + +if __name__ == "__main__": + main() diff --git a/scripts/modify_json.py b/scripts/modify_json.py deleted file mode 100644 index 83ccbf5d..00000000 --- a/scripts/modify_json.py +++ /dev/null @@ -1,40 +0,0 @@ -import json -import os -import random -import string - - -def load_json(file_path): - with open(file_path, 'r', encoding='utf-8') as file: - return json.load(file) - - -def save_json(data, file_path): - with open(file_path, 'w', encoding='utf-8') as file: - json.dump(data, file, ensure_ascii=False, indent=4) - - -def generate_random_string(length=8): - letters = string.ascii_lowercase - return ''.join(random.choice(letters) for i in range(length)) - - -def add_filename_field(data): - for item in data: - item['filename'] = generate_random_string() - return data - - -def main(): - # Use raw string (r) to avoid issues with backslashes - input_file_path = r'C:\Users\dotae\PycharmProjects\CescFe.github.io\tests\resources\books\sample_books.json' - output_file_path = r'C:\Users\dotae\PycharmProjects\CescFe.github.io\tests\resources\books\sample_books.json' - - data = load_json(input_file_path) - modified_data = add_filename_field(data) - save_json(modified_data, output_file_path) - print(f"Modified JSON has been saved to {output_file_path}") - - -if __name__ == "__main__": - main() From 532fd812fd6f324fb1ac3d9ed71438e069d3e398 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:29:34 +0200 Subject: [PATCH 03/10] Feat (ED-77): add env variables --- .gitignore | 5 +++-- scripts/collections_sheet_to_json.py | 14 ++++++++++---- scripts/utils/update_credentials.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 scripts/utils/update_credentials.py diff --git a/.gitignore b/.gitignore index d6a5a8b2..88d8864f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ assets/libs/ node_modules/ vendor .idea -scripts/credentials.json -scripts/token.json \ No newline at end of file +scripts/utils/credentials.json +scripts/token.json +.env \ No newline at end of file diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py index 68d67c3b..4ca86a58 100644 --- a/scripts/collections_sheet_to_json.py +++ b/scripts/collections_sheet_to_json.py @@ -9,11 +9,17 @@ SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] -COLLECTIONS_DENES_SHEET_ID = "1q_ityTPJaBxxmANQawi4Kjamq5wIVoQkahLsp63rP7g" -RANGE = "Sheet1" +DENES_SPREADSHEET_ID = os.environ.get('DENES_SPREADSHEET_ID') +RANGE = "collections" +CLIENT_ID_DENES_SHEET = os.environ.get('CLIENT_ID_DENES_SHEET') +CLIENT_SECRET_DENES_SHEET = os.environ.get('CLIENT_SECRET_DENES_SHEET') def main(): + if not CLIENT_ID_DENES_SHEET or not CLIENT_SECRET_DENES_SHEET or not DENES_SPREADSHEET_ID: + raise ValueError( + "Missing CLIENT_ID_DENES_SHEET or CLIENT_SECRET_DENES_SHEET or DENES_SPREADSHEET_ID environment variables") + credentials = None if os.path.exists("token.json"): credentials = Credentials.from_authorized_user_file("token.json", SCOPES) @@ -21,7 +27,7 @@ def main(): if credentials and credentials.expired and credentials.refresh_token: credentials.refresh(Request()) else: - flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES) + flow = InstalledAppFlow.from_client_secrets_file("utils/credentials.json", SCOPES) credentials = flow.run_local_server(port=0) with open("token.json", "w") as token: token.write(credentials.to_json()) @@ -30,7 +36,7 @@ def main(): service = build("sheets", "v4", credentials=credentials) sheets = service.spreadsheets() - result = sheets.values().get(spreadsheetId=COLLECTIONS_DENES_SHEET_ID, range=RANGE).execute() + result = sheets.values().get(spreadsheetId=DENES_SPREADSHEET_ID, range=RANGE).execute() values = result.get("values", []) diff --git a/scripts/utils/update_credentials.py b/scripts/utils/update_credentials.py new file mode 100644 index 00000000..e576c79d --- /dev/null +++ b/scripts/utils/update_credentials.py @@ -0,0 +1,28 @@ +import os +import json + +CLIENT_ID_DENES_SHEET = os.environ.get('CLIENT_ID_DENES_SHEET') +CLIENT_SECRET_DENES_SHEET = os.environ.get('CLIENT_SECRET_DENES_SHEET') + + +def update_credentials(): + if not CLIENT_ID_DENES_SHEET or not CLIENT_SECRET_DENES_SHEET: + raise ValueError("Missing CLIENT_ID_DENES_SHEET or CLIENT_SECRET_DENES_SHEET environment variables") + + # Load the existing credentials.json template + with open('credentials.json', 'r', encoding='utf-8') as file: + credentials = json.load(file) + + # Update the CLIENT_ID_DENES_SHEET and CLIENT_SECRET_DENES_SHEET + credentials['installed']['CLIENT_ID_DENES_SHEET'] = CLIENT_ID_DENES_SHEET + credentials['installed']['CLIENT_SECRET_DENES_SHEET'] = CLIENT_SECRET_DENES_SHEET + + # Save the updated credentials back to the file + with open('credentials.json', 'w', encoding='utf-8') as file: + json.dump(credentials, file, indent=4, ensure_ascii=False) + + print("Updated credentials.json with environment variables") + + +if __name__ == "__main__": + update_credentials() From f6abb394e66363569a971e95443dd6f6460168bf Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:23:47 +0200 Subject: [PATCH 04/10] Feat (ED-77): hide env vars --- .gitignore | 3 +-- scripts/collections_sheet_to_json.py | 19 ++++++++++++------- scripts/utils/update_credentials.py | 19 +++++++++++++------ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 88d8864f..f6d34e6d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,5 @@ assets/libs/ node_modules/ vendor .idea -scripts/utils/credentials.json -scripts/token.json +scripts/utils/token.json .env \ No newline at end of file diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py index 4ca86a58..3474f3f8 100644 --- a/scripts/collections_sheet_to_json.py +++ b/scripts/collections_sheet_to_json.py @@ -7,6 +7,8 @@ from googleapiclient.discovery import build from googleapiclient.errors import HttpError +from utils.update_credentials import update_credentials + SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] DENES_SPREADSHEET_ID = os.environ.get('DENES_SPREADSHEET_ID') @@ -16,20 +18,23 @@ def main(): - if not CLIENT_ID_DENES_SHEET or not CLIENT_SECRET_DENES_SHEET or not DENES_SPREADSHEET_ID: - raise ValueError( - "Missing CLIENT_ID_DENES_SHEET or CLIENT_SECRET_DENES_SHEET or DENES_SPREADSHEET_ID environment variables") + # Update credentials.json with environment variables + update_credentials() + + script_dir = os.path.dirname(os.path.abspath(__file__)) + credentials_path = os.path.join(script_dir, 'utils', 'credentials.json') + token_path = os.path.join(script_dir, 'utils', 'token.json') credentials = None - if os.path.exists("token.json"): - credentials = Credentials.from_authorized_user_file("token.json", SCOPES) + if os.path.exists("utils/token.json"): + credentials = Credentials.from_authorized_user_file("utils/token.json", SCOPES) if not credentials or not credentials.valid: if credentials and credentials.expired and credentials.refresh_token: credentials.refresh(Request()) else: - flow = InstalledAppFlow.from_client_secrets_file("utils/credentials.json", SCOPES) + flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES) credentials = flow.run_local_server(port=0) - with open("token.json", "w") as token: + with open(token_path, "w") as token: token.write(credentials.to_json()) try: diff --git a/scripts/utils/update_credentials.py b/scripts/utils/update_credentials.py index e576c79d..6d56de15 100644 --- a/scripts/utils/update_credentials.py +++ b/scripts/utils/update_credentials.py @@ -1,24 +1,31 @@ import os +from dotenv import load_dotenv import json -CLIENT_ID_DENES_SHEET = os.environ.get('CLIENT_ID_DENES_SHEET') -CLIENT_SECRET_DENES_SHEET = os.environ.get('CLIENT_SECRET_DENES_SHEET') +load_dotenv() + +CLIENT_ID_DENES_SHEET = os.getenv('CLIENT_ID_DENES_SHEET') +CLIENT_SECRET_DENES_SHEET = os.getenv('CLIENT_SECRET_DENES_SHEET') def update_credentials(): if not CLIENT_ID_DENES_SHEET or not CLIENT_SECRET_DENES_SHEET: raise ValueError("Missing CLIENT_ID_DENES_SHEET or CLIENT_SECRET_DENES_SHEET environment variables") + # Get the directory of the current script + script_dir = os.path.dirname(os.path.abspath(__file__)) + credentials_path = os.path.join(script_dir, 'credentials.json') + # Load the existing credentials.json template - with open('credentials.json', 'r', encoding='utf-8') as file: + with open(credentials_path, 'r', encoding='utf-8') as file: credentials = json.load(file) # Update the CLIENT_ID_DENES_SHEET and CLIENT_SECRET_DENES_SHEET - credentials['installed']['CLIENT_ID_DENES_SHEET'] = CLIENT_ID_DENES_SHEET - credentials['installed']['CLIENT_SECRET_DENES_SHEET'] = CLIENT_SECRET_DENES_SHEET + credentials['installed']['client_id'] = CLIENT_ID_DENES_SHEET + credentials['installed']['client_secret'] = CLIENT_SECRET_DENES_SHEET # Save the updated credentials back to the file - with open('credentials.json', 'w', encoding='utf-8') as file: + with open(credentials_path, 'w', encoding='utf-8') as file: json.dump(credentials, file, indent=4, ensure_ascii=False) print("Updated credentials.json with environment variables") From b9b62070fe8bb30a6011093802083f2bbadd33aa Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:24:00 +0200 Subject: [PATCH 05/10] Feat (ED-77): hide env vars --- scripts/utils/credentials.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 scripts/utils/credentials.json diff --git a/scripts/utils/credentials.json b/scripts/utils/credentials.json new file mode 100644 index 00000000..9dc2ab8c --- /dev/null +++ b/scripts/utils/credentials.json @@ -0,0 +1,13 @@ +{ + "installed": { + "client_id": "", + "project_id": "denessheetsproject", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_secret": "", + "redirect_uris": [ + "http://localhost" + ] + } +} \ No newline at end of file From f3fe835ba3d6bd555a0c9e4685ce305b7f62f36f Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:25:04 +0200 Subject: [PATCH 06/10] Feat (ED-77): hide env vars --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6d34e6d..8d0b0387 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ assets/libs/ node_modules/ vendor .idea +scripts/utils/credentials.json scripts/utils/token.json .env \ No newline at end of file From 8091a90636a7d5984c24c17b42085a07fc04e604 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:03:07 +0200 Subject: [PATCH 07/10] Feat (ED-77): update books.json --- scripts/resources/books.json | 50 +++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/scripts/resources/books.json b/scripts/resources/books.json index 71731c82..0152461c 100644 --- a/scripts/resources/books.json +++ b/scripts/resources/books.json @@ -3,8 +3,8 @@ "layout": "book", "title": "Gènesi de l'AVL. El Debat", "author": "Manuel Sanchis-Guarner Cabanilles", - "isbn": "9788416473632", - "pvp": "12.00", + "isbn": "978-84-16473-63-2", + "pvp": "12.00€", "year": 2024, "description": "Gènesi de l'AVL. El debat.", "description_long": "Manuel Sanchis-Guarner Cabanilles, fill de l'il·lustre filòleg, narra de primera mà el procés de debat al sí del Consell Valencià de Cultura que donà origen al dictamen de creació de l'Acadèmia Valenciana de la Llengua.", @@ -17,8 +17,8 @@ "layout": "book", "title": "L'aportació de Ferrer Pastor a la lexicografia catalano-valenciana", "author": "Emili Casanova", - "isbn": "9788416473588", - "pvp": "39.99", + "isbn": "978-84-16473-58-8", + "pvp": "39.99€", "year": 2022, "description": "L'aportació de Ferrer Pastor a la lexicografia catalano-valenciana. Paraules del Diccionari General, 1985 absents del diccionari Fabra, 1986, 22ªED.", "description_long": "En el present assaig, Emili Casanova analitza les aportacions a la llengua de l'obra de Ferrer Pastor.", @@ -26,5 +26,47 @@ "category": "poesia", "img": "assets/img/collection_preview/collection_default.png", "filename": "aportacio-ferrer-pastor-a-la-lexicografia" + }, + { + "layout": "book", + "title": "Diccionari Valencià Escolar Il·lustrat (Senzill)", + "author": "Francesc Ferrer Pastor", + "isbn": "978-84-96545-35-9", + "pvp": "11.95€", + "year": 2024, + "description": "Diccionari Valencià Escolar Il·lustrat (Valencià - Castellà)", + "description_long": "El Diccionari Valencià Escolar Il·lustrat de Francesc Ferrer Pastor és una eina fonamental per a estudiants i docents. Aquest diccionari ofereix una doble funció: d'una banda, proporciona la traducció i definició clara i precisa de paraules en valencià; de l'altra, inclou il·lustracions que faciliten la comprensió visual dels termes. Aquest diccionari és ideal per a l'aprenentatge a les escoles. Francesc Ferrer Pastor, reconegut lexicògraf, va elaborar aquesta obra amb rigor i passió per la llengua, fent-la accessible i atractiva per als joves lectors.", + "importance": 3, + "category": "diccionari", + "img": "assets/img/book_covers/dicc_senzill.png", + "filename": "diccionari-escolar-illustrat" + }, + { + "layout": "book", + "title": "Vocabulari Il·lustrat", + "author": "Francesc Ferrer Pastor", + "isbn": "978-84-96545-33-5", + "pvp": "14.96€", + "year": 2024, + "description": "Vocabulari Il·lustrat (Castellà - Valencià | Valencià - Castellà)", + "description_long": "El Vocabulari Il·lustrat de Francesc Ferrer Pastor és una eina fonamental per a estudiants i docents. Aquest vocabulari ofereix una doble funció: d'una banda, proporciona la traducció i definició clara i precisa de paraules tant en valencià com en castellà; de l'altra, inclou il·lustracions que faciliten la comprensió visual dels termes. Aquest vocabulari és ideal per a l'aprenentatge a les escoles. Francesc Ferrer Pastor, reconegut lexicògraf, va elaborar aquesta obra amb rigor i passió per la llengua, fent-la accessible i atractiva per als joves lectors.", + "importance": 1, + "category": "diccionari", + "img": "assets/img/book_covers/vocabulari.png", + "filename": "vocabulari-illustrat" + }, + { + "layout": "book", + "title": "Diccionari Valencià Escolar Il·lustrat (Doble)", + "author": "Francesc Ferrer Pastor", + "isbn": "978-84-96545-34-2", + "pvp": "15.85€", + "year": 2024, + "description": "Diccionari Valencià Escolar Il·lustrat (Valencià - Castellà | Castellà - Valencià)", + "description_long": "El Diccionari Valencià Escolar Il·lustrat (Valencià - Castellà | Castellà - Valencià) de Francesc Ferrer Pastor és una eina fonamental per a estudiants i docents. Aquest diccionari ofereix una doble funció: d'una banda, proporciona la traducció i definició clara i precisa de paraules tant en valencià com en castellà; de l'altra, inclou il·lustracions que faciliten la comprensió visual dels termes. Aquest diccionari és ideal per a l'aprenentatge a les escoles. Francesc Ferrer Pastor, reconegut lexicògraf, va elaborar aquesta obra amb rigor i passió per la llengua, fent-la accessible i atractiva per als joves lectors.", + "importance": 2, + "category": "diccionari", + "img": "assets/img/book_covers/dicc_doble.png", + "filename": "diccionari-escolar-doble-illustrat" } ] From cce6e539b579f830bee88d0c7e5d2c7bb6e26cc5 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:59:39 +0200 Subject: [PATCH 08/10] Feat (ED-77): refactor sheet to json script --- scripts/collections_sheet_to_json.py | 72 ++++++++++++---------- scripts/utils/credentials_sheet_handler.py | 51 +++++++++++++++ scripts/utils/update_credentials.py | 35 ----------- 3 files changed, 92 insertions(+), 66 deletions(-) create mode 100644 scripts/utils/credentials_sheet_handler.py delete mode 100644 scripts/utils/update_credentials.py diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py index 3474f3f8..c67f05fe 100644 --- a/scripts/collections_sheet_to_json.py +++ b/scripts/collections_sheet_to_json.py @@ -1,5 +1,6 @@ import os.path import json +from dotenv import load_dotenv from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials @@ -7,27 +8,23 @@ from googleapiclient.discovery import build from googleapiclient.errors import HttpError -from utils.update_credentials import update_credentials +from utils.credentials_sheet_handler import update_credentials, get_absolute_path +load_dotenv() SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] - DENES_SPREADSHEET_ID = os.environ.get('DENES_SPREADSHEET_ID') -RANGE = "collections" +FETCH_RANGE = "collections" CLIENT_ID_DENES_SHEET = os.environ.get('CLIENT_ID_DENES_SHEET') CLIENT_SECRET_DENES_SHEET = os.environ.get('CLIENT_SECRET_DENES_SHEET') +CREDENTIALS_FILENAME = "credentials.json" +TOKEN_FILENAME = "token.json" +OUTPUT_COLLECTIONS_FILE = "collections.json" -def main(): - # Update credentials.json with environment variables - update_credentials() - - script_dir = os.path.dirname(os.path.abspath(__file__)) - credentials_path = os.path.join(script_dir, 'utils', 'credentials.json') - token_path = os.path.join(script_dir, 'utils', 'token.json') - +def get_credentials(credentials_path, token_path): credentials = None - if os.path.exists("utils/token.json"): - credentials = Credentials.from_authorized_user_file("utils/token.json", SCOPES) + if os.path.exists(get_absolute_path(TOKEN_FILENAME)): + credentials = Credentials.from_authorized_user_file(get_absolute_path(TOKEN_FILENAME), SCOPES) if not credentials or not credentials.valid: if credentials and credentials.expired and credentials.refresh_token: credentials.refresh(Request()) @@ -36,36 +33,49 @@ def main(): credentials = flow.run_local_server(port=0) with open(token_path, "w") as token: token.write(credentials.to_json()) + return credentials + +def fetch_sheet_data(credentials, spreadsheet_id, fetch_range): try: service = build("sheets", "v4", credentials=credentials) sheets = service.spreadsheets() + result = sheets.values().get(spreadsheetId=spreadsheet_id, range=fetch_range).execute() + return result.get("values", []) + except HttpError as error: + print(error) - result = sheets.values().get(spreadsheetId=DENES_SPREADSHEET_ID, range=RANGE).execute() - values = result.get("values", []) +def transform_to_json(values): + if not values: + print("No data found.") + return [] - if not values: - print("No data found.") - return + header = values[0] + data = [] + # Transform rows into a list of dictionaries + for row in values[1:]: + row_data = {header[i]: row[i] if i < len(row) else "" for i in range(len(header))} + data.append(row_data) + return data - # Extract header - header = values[0] - data = [] - # Transform rows into a list of dictionaries - for row in values[1:]: - row_data = {header[i]: row[i] if i < len(row) else "" for i in range(len(header))} - data.append(row_data) +def write_to_file(data, filename): + with open(filename, "w", encoding='utf-8') as json_file: + json.dump(data, json_file, indent=4, ensure_ascii=False) + print(f"Data has been written to {filename}") - # Write data to collections.json file - with open("collections.json", "w", encoding='utf-8') as json_file: - json.dump(data, json_file, indent=4, ensure_ascii=False) - print("Data has been written to collections.json") +def main(): + credentials_path = get_absolute_path(CREDENTIALS_FILENAME) + update_credentials(CLIENT_ID_DENES_SHEET, CLIENT_SECRET_DENES_SHEET, credentials_path) - except HttpError as error: - print(error) + token_path = get_absolute_path(TOKEN_FILENAME) + + credentials = get_credentials(credentials_path, token_path) + values = fetch_sheet_data(credentials, DENES_SPREADSHEET_ID, FETCH_RANGE) + data = transform_to_json(values) + write_to_file(data, OUTPUT_COLLECTIONS_FILE) if __name__ == "__main__": diff --git a/scripts/utils/credentials_sheet_handler.py b/scripts/utils/credentials_sheet_handler.py new file mode 100644 index 00000000..68f562c4 --- /dev/null +++ b/scripts/utils/credentials_sheet_handler.py @@ -0,0 +1,51 @@ +import os +import json +from dotenv import load_dotenv + + +def check_environment_variables(client_id_denes_sheet, client_secret_denes_sheet): + if not client_id_denes_sheet or not client_secret_denes_sheet: + raise ValueError("Missing client_id_denes_sheet or client_secret_denes_sheet environment variables") + + +def get_absolute_path(credentials_relative_path): + script_dir = os.path.dirname(os.path.abspath(__file__)) + credentials_path = os.path.join(script_dir, credentials_relative_path) + return credentials_path + + +def load_credentials(credentials_path): + with open(credentials_path, 'r', encoding='utf-8') as file: + credentials = json.load(file) + return credentials + + +def update_credentials_data(credentials, client_id_denes_sheet, client_secret_denes_sheet): + credentials['installed']['client_id'] = client_id_denes_sheet + credentials['installed']['client_secret'] = client_secret_denes_sheet + + +def save_credentials(credentials, credentials_path): + with open(credentials_path, 'w', encoding='utf-8') as file: + json.dump(credentials, file, indent=4, ensure_ascii=False) + print("Updated credentials.json with environment variables") + + +def update_credentials(client_id_denes_sheet, client_secret_denes_sheet, credentials_path): + check_environment_variables(client_id_denes_sheet, client_secret_denes_sheet) + credentials = load_credentials(credentials_path) + update_credentials_data(credentials, client_id_denes_sheet, client_secret_denes_sheet) + save_credentials(credentials, credentials_path) + + +def main(): + load_dotenv() + credentials_relative_path = "credentials.json" + client_id_denes_sheet = os.getenv('CLIENT_ID_DENES_SHEET') + client_secret_denes_sheet = os.getenv('CLIENT_SECRET_DENES_SHEET') + credentials_path = get_absolute_path(credentials_relative_path) + update_credentials(client_id_denes_sheet, client_secret_denes_sheet, credentials_path) + + +if __name__ == "__main__": + main() diff --git a/scripts/utils/update_credentials.py b/scripts/utils/update_credentials.py deleted file mode 100644 index 6d56de15..00000000 --- a/scripts/utils/update_credentials.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from dotenv import load_dotenv -import json - -load_dotenv() - -CLIENT_ID_DENES_SHEET = os.getenv('CLIENT_ID_DENES_SHEET') -CLIENT_SECRET_DENES_SHEET = os.getenv('CLIENT_SECRET_DENES_SHEET') - - -def update_credentials(): - if not CLIENT_ID_DENES_SHEET or not CLIENT_SECRET_DENES_SHEET: - raise ValueError("Missing CLIENT_ID_DENES_SHEET or CLIENT_SECRET_DENES_SHEET environment variables") - - # Get the directory of the current script - script_dir = os.path.dirname(os.path.abspath(__file__)) - credentials_path = os.path.join(script_dir, 'credentials.json') - - # Load the existing credentials.json template - with open(credentials_path, 'r', encoding='utf-8') as file: - credentials = json.load(file) - - # Update the CLIENT_ID_DENES_SHEET and CLIENT_SECRET_DENES_SHEET - credentials['installed']['client_id'] = CLIENT_ID_DENES_SHEET - credentials['installed']['client_secret'] = CLIENT_SECRET_DENES_SHEET - - # Save the updated credentials back to the file - with open(credentials_path, 'w', encoding='utf-8') as file: - json.dump(credentials, file, indent=4, ensure_ascii=False) - - print("Updated credentials.json with environment variables") - - -if __name__ == "__main__": - update_credentials() From e8691eccfcf8187143c40a0e65e7f1700a7fd4b1 Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:49:45 +0200 Subject: [PATCH 09/10] Feat (ED-77): refactor sheet to json script --- scripts/collections_sheet_to_json.py | 24 +---------- scripts/utils/credentials_sheet_handler.py | 47 +++++++++++++++------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py index c67f05fe..17a876da 100644 --- a/scripts/collections_sheet_to_json.py +++ b/scripts/collections_sheet_to_json.py @@ -2,13 +2,10 @@ import json from dotenv import load_dotenv -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials -from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError -from utils.credentials_sheet_handler import update_credentials, get_absolute_path +from utils.credentials_sheet_handler import update_credentials, get_absolute_path, get_credentials load_dotenv() SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] @@ -21,21 +18,6 @@ OUTPUT_COLLECTIONS_FILE = "collections.json" -def get_credentials(credentials_path, token_path): - credentials = None - if os.path.exists(get_absolute_path(TOKEN_FILENAME)): - credentials = Credentials.from_authorized_user_file(get_absolute_path(TOKEN_FILENAME), SCOPES) - if not credentials or not credentials.valid: - if credentials and credentials.expired and credentials.refresh_token: - credentials.refresh(Request()) - else: - flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES) - credentials = flow.run_local_server(port=0) - with open(token_path, "w") as token: - token.write(credentials.to_json()) - return credentials - - def fetch_sheet_data(credentials, spreadsheet_id, fetch_range): try: service = build("sheets", "v4", credentials=credentials) @@ -69,10 +51,8 @@ def write_to_file(data, filename): def main(): credentials_path = get_absolute_path(CREDENTIALS_FILENAME) update_credentials(CLIENT_ID_DENES_SHEET, CLIENT_SECRET_DENES_SHEET, credentials_path) + credentials = get_credentials(credentials_path, get_absolute_path(TOKEN_FILENAME), SCOPES) - token_path = get_absolute_path(TOKEN_FILENAME) - - credentials = get_credentials(credentials_path, token_path) values = fetch_sheet_data(credentials, DENES_SPREADSHEET_ID, FETCH_RANGE) data = transform_to_json(values) write_to_file(data, OUTPUT_COLLECTIONS_FILE) diff --git a/scripts/utils/credentials_sheet_handler.py b/scripts/utils/credentials_sheet_handler.py index 68f562c4..6d43b5b4 100644 --- a/scripts/utils/credentials_sheet_handler.py +++ b/scripts/utils/credentials_sheet_handler.py @@ -2,33 +2,37 @@ import json from dotenv import load_dotenv +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow + def check_environment_variables(client_id_denes_sheet, client_secret_denes_sheet): if not client_id_denes_sheet or not client_secret_denes_sheet: - raise ValueError("Missing client_id_denes_sheet or client_secret_denes_sheet environment variables") + raise ValueError(f"Missing {client_id_denes_sheet} or {client_secret_denes_sheet} environment variables") def get_absolute_path(credentials_relative_path): script_dir = os.path.dirname(os.path.abspath(__file__)) - credentials_path = os.path.join(script_dir, credentials_relative_path) - return credentials_path + credentials_absolute_path = os.path.join(script_dir, credentials_relative_path) + return credentials_absolute_path -def load_credentials(credentials_path): - with open(credentials_path, 'r', encoding='utf-8') as file: - credentials = json.load(file) - return credentials +def load_credentials(credentials_absolute_path): + with open(credentials_absolute_path, 'r', encoding='utf-8') as json_file: + credentials_json_data = json.load(json_file) + return credentials_json_data -def update_credentials_data(credentials, client_id_denes_sheet, client_secret_denes_sheet): - credentials['installed']['client_id'] = client_id_denes_sheet - credentials['installed']['client_secret'] = client_secret_denes_sheet +def update_credentials_data(credentials_json_data, client_id_denes_sheet, client_secret_denes_sheet): + credentials_json_data['installed']['client_id'] = client_id_denes_sheet + credentials_json_data['installed']['client_secret'] = client_secret_denes_sheet -def save_credentials(credentials, credentials_path): - with open(credentials_path, 'w', encoding='utf-8') as file: - json.dump(credentials, file, indent=4, ensure_ascii=False) - print("Updated credentials.json with environment variables") +def save_credentials(credentials_json_data, credentials_path): + with open(credentials_path, 'w', encoding='utf-8') as json_file: + json.dump(credentials_json_data, json_file, indent=4, ensure_ascii=False) + print(f"Updated {credentials_path} with environment variables") def update_credentials(client_id_denes_sheet, client_secret_denes_sheet, credentials_path): @@ -47,5 +51,20 @@ def main(): update_credentials(client_id_denes_sheet, client_secret_denes_sheet, credentials_path) +def get_credentials(credentials_path, token_filename, scopes): + credentials = None + if os.path.exists(get_absolute_path(token_filename)): + credentials = Credentials.from_authorized_user_file(get_absolute_path(token_filename), scopes) + if not credentials or not credentials.valid: + if credentials and credentials.expired and credentials.refresh_token: + credentials.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes) + credentials = flow.run_local_server(port=0) + with open(get_absolute_path(token_filename), "w") as token: + token.write(credentials.to_json()) + return credentials + + if __name__ == "__main__": main() From c3ef176d7e523704cb99b1377c570419e562000f Mon Sep 17 00:00:00 2001 From: Cesc Fe <76252400+FrancescFe@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:13:26 +0200 Subject: [PATCH 10/10] Feat (ED-77): refactor sheet to json script --- scripts/collections_sheet_to_json.py | 16 ++-------- scripts/utils/credentials_sheet_handler.py | 19 ------------ scripts/utils/google_libs_handler.py | 34 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 scripts/utils/google_libs_handler.py diff --git a/scripts/collections_sheet_to_json.py b/scripts/collections_sheet_to_json.py index 17a876da..86f89abc 100644 --- a/scripts/collections_sheet_to_json.py +++ b/scripts/collections_sheet_to_json.py @@ -2,10 +2,8 @@ import json from dotenv import load_dotenv -from googleapiclient.discovery import build -from googleapiclient.errors import HttpError - -from utils.credentials_sheet_handler import update_credentials, get_absolute_path, get_credentials +from utils.credentials_sheet_handler import update_credentials, get_absolute_path +from utils.google_libs_handler import get_credentials, fetch_sheet_data load_dotenv() SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"] @@ -18,16 +16,6 @@ OUTPUT_COLLECTIONS_FILE = "collections.json" -def fetch_sheet_data(credentials, spreadsheet_id, fetch_range): - try: - service = build("sheets", "v4", credentials=credentials) - sheets = service.spreadsheets() - result = sheets.values().get(spreadsheetId=spreadsheet_id, range=fetch_range).execute() - return result.get("values", []) - except HttpError as error: - print(error) - - def transform_to_json(values): if not values: print("No data found.") diff --git a/scripts/utils/credentials_sheet_handler.py b/scripts/utils/credentials_sheet_handler.py index 6d43b5b4..cba0d870 100644 --- a/scripts/utils/credentials_sheet_handler.py +++ b/scripts/utils/credentials_sheet_handler.py @@ -2,10 +2,6 @@ import json from dotenv import load_dotenv -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials -from google_auth_oauthlib.flow import InstalledAppFlow - def check_environment_variables(client_id_denes_sheet, client_secret_denes_sheet): if not client_id_denes_sheet or not client_secret_denes_sheet: @@ -51,20 +47,5 @@ def main(): update_credentials(client_id_denes_sheet, client_secret_denes_sheet, credentials_path) -def get_credentials(credentials_path, token_filename, scopes): - credentials = None - if os.path.exists(get_absolute_path(token_filename)): - credentials = Credentials.from_authorized_user_file(get_absolute_path(token_filename), scopes) - if not credentials or not credentials.valid: - if credentials and credentials.expired and credentials.refresh_token: - credentials.refresh(Request()) - else: - flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes) - credentials = flow.run_local_server(port=0) - with open(get_absolute_path(token_filename), "w") as token: - token.write(credentials.to_json()) - return credentials - - if __name__ == "__main__": main() diff --git a/scripts/utils/google_libs_handler.py b/scripts/utils/google_libs_handler.py new file mode 100644 index 00000000..5ff3b2f0 --- /dev/null +++ b/scripts/utils/google_libs_handler.py @@ -0,0 +1,34 @@ +import os + +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError + +from .credentials_sheet_handler import get_absolute_path + + +def get_credentials(credentials_path, token_filename, scopes): + credentials = None + if os.path.exists(get_absolute_path(token_filename)): + credentials = Credentials.from_authorized_user_file(get_absolute_path(token_filename), scopes) + if not credentials or not credentials.valid: + if credentials and credentials.expired and credentials.refresh_token: + credentials.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes) + credentials = flow.run_local_server(port=0) + with open(get_absolute_path(token_filename), "w") as token: + token.write(credentials.to_json()) + return credentials + + +def fetch_sheet_data(credentials, spreadsheet_id, fetch_range): + try: + service = build("sheets", "v4", credentials=credentials) + sheets = service.spreadsheets() + result = sheets.values().get(spreadsheetId=spreadsheet_id, range=fetch_range).execute() + return result.get("values", []) + except HttpError as error: + print(error)