Skip to main content

Changes not applied to Excel file after calculation using MS Graph API

I'm using Python to create a wrapper for MS Graph Excel API to handle calculation.

from typing import Any, Union
from urllib.parse import urljoin

import requests


class MsGraph:
    _graph_uri = "https://graph.microsoft.com/v1.0/"

    def __init__(self, token: str, file_path: str):
        self.file_path = file_path
        self.token = token
        self.request_headers = {"Authorization": f"Bearer {self.token}"}

    def _call_api(self, endpoint: str, req_type="GET", payload=None, headers=None) -> Any:
        if headers:
            headers.update(self.request_headers)
        else:
            headers = self.request_headers
        endpoint = self._sanitize_endpoint(endpoint)

        kwargs = {"headers": headers}

        if payload:
            kwargs["json" if "json" in headers.get("Content-Type") else "data"] = payload

        resp = requests.request(req_type, endpoint, **kwargs)
        resp.raise_for_status()
        if resp.status_code is requests.codes.no_content:
            return resp.text

        if resp.status_code is requests.codes.found:
            return resp.text

        return resp.json()

    def _sanitize_endpoint(self, uri: str) -> str:
        if uri.startswith(self._graph_uri):
            return uri
        return urljoin(self._graph_uri, uri)

    def list_onedrive_files_for_auth_user(self) -> Any:
        return self._call_api("me/drive/root/children")

    def get_onedrive_id_from_user(self) -> Any:
        return self._call_api("me/drives")

    def get_onedrive_id_for_app(self) -> Any:
        return self._call_api("drives")

    def upload_to_onedrive(self, file_name: str, content: Union[bytes, str]) -> Any:
        """content: file content in the text/binary form """
        headers = {"Content-Type": "text/plain"}
        drive_uri = f"me/drive/root:/{file_name}:/content"
        return self._call_api(drive_uri, "PUT", content, headers)

    def excel_read(self, drive_item_id: Any) -> Any:
        return self._call_api(f"me/drive/items/{drive_item_id}/workbook/worksheets")

    def excel_create_session(self, drive_item_id: Any) -> Any:
        headers = {"Content-Type": "application/json"}
        payload = {"persistChanges": True}

        uri = f"me/drive/items/{drive_item_id}/workbook/createSession"
        return self._call_api(uri, "POST", payload, headers)

    def excel_close_session(self, drive_item_id: Any, persist_session_id: str) -> Any:
        headers = {
            "Content-Type": "application/json",
            "workbook-session-id": persist_session_id
        }

        uri = f"me/drive/items/{drive_item_id}/workbook/closeSession"
        return self._call_api(uri, "POST", None, headers)

    def excel_calculate(self, drive_item_id: Any, persist_session_id: str, calc_type="FullRebuild") -> Any:
        supported_types = ["Recalculate", "Full", "FullRebuild"]
        if calc_type not in supported_types:
            raise AttributeError(
                f"calculation type '{calc_type}' need to be one of supported: {supported_types}"
            )
        headers = {
            "Content-Type": "application/json",
            "workbook-session-id": persist_session_id
        }
        payload = {"calculationType": calc_type}

        calc_uri = f"me/drive/items/{drive_item_id}/workbook/application/calculate"
        return self._call_api(calc_uri, "POST", payload, headers)

    def download_from_onedrive(self, drive_item_id: Any, file_path: str) -> None:
        uri = f"{self._graph_uri}/me/drive/items/{drive_item_id}/content"
        response = requests.get(uri, headers=self.request_headers)
        with open(file_path, "wb") as handle:
            handle.write(response.content)

    def delete_from_onedrive(self, drive_item_id: Any) -> Any:
        drive_uri = f"me/drive/items/{drive_item_id}"
        return self._call_api(drive_uri, "DELETE")

    def read_excel_from_path(self) -> bytes:
        with open(self.file_path, "rb") as excel_file:
            return excel_file.read()

I managed to authorize and get tokens. File uploads correctly, persistent session creates correctly, calculation triggers without any errors, but after all I want to download the Excel file with recalculated formulas. Unfortunately, formulas didn't reevaluate and I see the old data (doing this programatically using Apache POI).

        msgraph = MsGraph(token, file_path)
        excel_file_content = msgraph.read_excel_from_path()

        file_name = os.path.basename(file_path)
        drive_item = msgraph.upload_to_onedrive(file_name, excel_file_content)
        persist_session_response = msgraph.excel_create_session(drive_item["id"])
        msgraph.excel_calculate(drive_item["id"], persist_session_response["id"])
        msgraph.excel_close_session(drive_item["id"], persist_session_response["id"])
        msgraph.download_from_onedrive(drive_item["id"], file_path)
        msgraph.delete_from_onedrive(drive_item["id"])

Excel formulas seem to be filled correctly, because when I open them with Excel Online GUI and trigger reevaluation/calculation with F9, everything gets updated correctly. Not sure what I'm doing wrong. Tried { persistSession: true } (and false and without creating a session).



source https://stackoverflow.com/questions/73057052/changes-not-applied-to-excel-file-after-calculation-using-ms-graph-api

Comments

Popular posts from this blog

Prop `className` did not match in next js app

I have written a sample code ( Github Link here ). this is a simple next js app, but giving me error when I refresh the page. This seems to be the common problem and I tried the fix provided in the internet but does not seem to fix my issue. The error is Warning: Prop className did not match. Server: "MuiBox-root MuiBox-root-1" Client: "MuiBox-root MuiBox-root-2". Did changes for _document.js, modified _app.js as mentioned in official website and solutions in stackoverflow. but nothing seems to work. Could someone take a look and help me whats wrong with the code? Via Active questions tagged javascript - Stack Overflow https://ift.tt/2FdjaAW

How to show number of registered users in Laravel based on usertype?

i'm trying to display data from the database in the admin dashboard i used this: <?php use Illuminate\Support\Facades\DB; $users = DB::table('users')->count(); echo $users; ?> and i have successfully get the correct data from the database but what if i want to display a specific data for example in this user table there is "usertype" that specify if the user is normal user or admin i want to user the same code above but to display a specific usertype i tried this: <?php use Illuminate\Support\Facades\DB; $users = DB::table('users')->count()->WHERE usertype =admin; echo $users; ?> but it didn't work, what am i doing wrong? source https://stackoverflow.com/questions/68199726/how-to-show-number-of-registered-users-in-laravel-based-on-usertype

Why is my reports service not connecting?

I am trying to pull some data from a Postgres database using Node.js and node-postures but I can't figure out why my service isn't connecting. my routes/index.js file: const express = require('express'); const router = express.Router(); const ordersCountController = require('../controllers/ordersCountController'); const ordersController = require('../controllers/ordersController'); const weeklyReportsController = require('../controllers/weeklyReportsController'); router.get('/orders_count', ordersCountController); router.get('/orders', ordersController); router.get('/weekly_reports', weeklyReportsController); module.exports = router; My controllers/weeklyReportsController.js file: const weeklyReportsService = require('../services/weeklyReportsService'); const weeklyReportsController = async (req, res) => { try { const data = await weeklyReportsService; res.json({data}) console