def test_upsert_existing_rows(self, main_table): columns = main_table.columns() key_column = columns[0] result = main_table.upsert_rows( [ [Cell(column, f"value-{str(row)}-{column.name}") for column in columns] for row in range(1, 11) ] ) assert result["status"] == 200 cell_to_update_1 = Cell(key_column, f"value-5-{columns[0].name}") cell_to_update_2 = Cell(columns[1], "updated_value") row_to_update = [cell_to_update_1, cell_to_update_2] result = main_table.upsert_rows([row_to_update], key_columns=[key_column]) assert result["status"] == 200 updated_rows = main_table.find_row_by_column_id_and_value( cell_to_update_1.column.id, cell_to_update_1.value ) assert len(updated_rows) == 1 updated_row = updated_rows[0] assert ( updated_row.get_cell_by_column_id(columns[1].id).value == cell_to_update_2.value )
def test_upsert_row(self, main_table): columns = main_table.columns() cell_1 = Cell(columns[0], f"value-{columns[0].name}") cell_2 = Cell(columns[1], f"value-{columns[1].name}") result = main_table.upsert_row([cell_1, cell_2]) assert result["status"] == 200 rows = main_table.find_row_by_column_id_and_value( cell_1.column.id, cell_1.value ) row = rows[0] assert isinstance(row, Row) assert row[cell_1.column.id].value == cell_1.value assert row[cell_2.column.id].value == cell_2.value
def test_upsert_row(self, main_table): columns = main_table.columns() cell_1 = Cell(columns[0], "unique_value_1") cell_2 = Cell(columns[1], "unique_value_2") result = main_table.upsert_row([cell_1, cell_2]) assert result["status"] == 202 rows = None count = 0 while not rows: count += 1 rows = main_table.find_row_by_column_id_and_value( cell_1.column.id, cell_1.value) if count > 20: pytest.fail("Row not added to table after 20 seconds") time.sleep(1) row = rows[0] assert isinstance(row, Row) assert row[cell_1.column.id].value == cell_1.value assert row[cell_2.column.id].value == cell_2.value
def sync_tasks(coda_table, todoist_tasks) -> None: """ Sync tasks between todoist and coda.io Parameters ---------- coda_table todoist_tasks Returns ------- None """ coda_rows = coda_table.rows() coda_tasks_w_taxid: List[Row] = [] coda_tasks_wo_taxid: List[Row] = [] coda_taskids = [] for coda_row in coda_rows: coda_row_data = coda_row.to_dict() if coda_row_data["Task ID"] == "": coda_tasks_wo_taxid.append(coda_row) else: coda_tasks_w_taxid.append(coda_row) coda_taskids.append(coda_row_data["Task ID"]) # 1. Additions: Todoist -> Coda # Todoist tasks with Task IDs not in Coda get added cells_list = [] for todoist_task in todoist_tasks: if todoist_task["id"] not in coda_taskids: cells = todoist_to_coda_converter(todoist_task, coda_table.columns()) cells_list.append(cells) coda_table.upsert_rows(cells_list) # 2. Additions: Coda -> Todoist # Coda tasks without Task IDs are added to Todoist # New TaskID is created and copied over to Coda for coda_task in coda_tasks_wo_taxid: todoist_task_dict = coda_to_todoist_converter(coda_task) TODOIST_API.items.add(**todoist_task_dict) todoist_task_dict_committed = TODOIST_API.commit() coda_taskid_cell = Cell("Task ID", todoist_task_dict_committed["id"]) coda_table.update_row(coda_task, coda_taskid_cell) # 3. Updates: Coda <-> Todoist # Common tasks are updated based on last modified # FIXME: Only syncs changes from Coda -> Todoist (since todoist items don't have a modified entry) for coda_row in coda_rows: coda_row_data = coda_row.to_dict() modified_on = pendulum.parse(coda_row_data["Modified on"]) created_on = pendulum.parse(coda_row_data["Created on"]) if modified_on > created_on: todoist_task_dict = coda_to_todoist_converter(coda_row) TODOIST_API.items.update(todoist_task_dict["id"], **todoist_task_dict) TODOIST_API.commit()
def test_upsert_rows(self, main_table): columns = main_table.columns() rows = [] for row in range(1, 11): rows.append([ Cell(column, f"value-{str(row)}-{column.name}") for column in columns ]) result = main_table.upsert_rows(rows) assert result["status"] == 202 key_column = columns[0] cell_to_update_1 = Cell(key_column, f"value-5-{columns[0].name}") cell_to_update_2 = Cell(columns[1], "updated_value") row_to_update = [cell_to_update_1, cell_to_update_2] result = main_table.upsert_rows([row_to_update], key_columns=[key_column]) assert result["status"] == 202 updated_rows = None while not updated_rows: updated_rows = main_table.find_row_by_column_id_and_value( cell_to_update_1.column.id, cell_to_update_1.value) time.sleep(1) assert len(updated_rows) == 1 updated_row = updated_rows[0] assert (updated_row.get_cell_by_column_id( columns[1].id).value == cell_to_update_2.value)
def todoist_to_coda_converter(todoist_item: Item, coda_columns: List[Column]) -> List[Cell]: """ Convert todoist `Item` object into a list of Coda `Cell` objects Parameters ---------- todoist_item : Item The todoist `Item` object to be converted coda_columns : List[Column] The list of coda `Column` objects Returns ------- List[Cell] The list of coda cells that will form the new row in the coda table """ coda_cells: List[Cell] = [] coda_column_dict = {col.name: col for col in coda_columns} for todoist_col, coda_col in zip(TODOIST_COLS, CODA_COLS): if todoist_col == "due date": if todoist_item.data["due"]: value = todoist_item.data["due"]["date"] else: value = "" elif todoist_col == "labels": value = [] label_dict = get_todoist_labels() for label_id in todoist_item.data["labels"]: value.append(label_dict[label_id]["name"]) elif todoist_col == "project_id": project_dict = get_todoist_projects() project_id = todoist_item.data["project_id"] value = project_dict[project_id]["name"] elif todoist_col == "parent_id": task_dict = get_todoist_tasks() task_id = todoist_item.data["parent_id"] try: value = task_dict[task_id]["content"] except KeyError: value = None else: value = todoist_item.data[todoist_col] coda_cells.append(Cell(coda_column_dict[coda_col], value)) return coda_cells
def test_upsert_rows_by_column_id(self, main_table): existing_rows = main_table.rows() for row in existing_rows: main_table.delete_row(row) result = main_table.upsert_rows( [ [ Cell(column.id, f"value-{str(row)}-{column.name}") for column in main_table.columns() ] for row in range(1, 6) ] ) assert result["status"] == 200 saved_rows = main_table.rows() assert len(saved_rows) == 5 assert all([isinstance(row, Row) for row in saved_rows])
def report_usage_to_coda(): """ report key performance metrics to coda.io runs only if `CODA_API_KEY` is set. It should only be configured in production to prevent reporting data from local or staging environments. """ if not settings.CODA_API_KEY: return "CODA_API_KEY is not set." coda = Coda(settings.CODA_API_KEY) doc_id, table_id = settings.CODA_DOC_ID, settings.CODA_TABLE_ID doc = Document(doc_id, coda=coda) table = doc.get_table(table_id) rows = [] for user in User.objects.exclude(athlete=None): mapping = { "ID": user.id, "Username": user.username, "Email": user.email, "Date Joined": user.date_joined.__str__(), "Last Login": user.last_login.__str__(), "Routes Count": user.athlete.tracks.count(), "Strava Activities Count": user.athlete.activities.count(), } try: rows.append([ Cell(column=table.get_column_by_name(key), value_storage=value) for key, value in mapping.items() ]) except codaio.err.ColumnNotFound as error: message = f"Missing column in coda document at https://coda.io/d/{doc_id}: {error}" logger.error(message) raise ImproperlyConfigured(message) table.upsert_rows(rows, key_columns=["ID"]) return f"Updated {len(rows)} rows in Coda table at https://coda.io/d/{doc_id}"