Post request in JupyterLab server extension breaks when calling imported function - python

I'm working on creating a JupyterLab server-side extension from this template and am having trouble calling an imported python function in the post method of handlers.py. The post request is sent from my index.ts file with a body containing the relative path of the active notebook when the user presses the "Measure Energy Usage" button. Sending it works fine if I leave out the call to measure_cell2.measure() in handlers.py. However, when I try to call that function, I get these errors on the right from the post request:
In the terminal running jupyter lab, I get this error:
[W 2021-07-13 12:42:47.633 ServerApp] 404 POST /jlab-ext-example/hello?1626198167480 (127.0.0.1) 7.70ms referer=http://localhost:8888/lab/tree/jupyter_lab_ext/jlab_ext_example/nbtest2.ipynb
I know that abs_path is the correct path, because when I leave out the measure function call in handlers.py, simply print the path returned by os.path.abspath, and then run the measure function directly from the python console or the terminal using that path, it produces the desired output. The post method in handlers.py doesn't seem to be executing at all since print(abs_path) is never executed and it comes before the call to measure. What could be causing this error?
JupyterLab 3.0.16,
Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-143-generic x86_64),
Python 3.9.5,
Node v14.8.0,
tsc 2.7.2
index.ts:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { IRetroShell } from '#retrolab/application';
import { ICommandPalette } from '#jupyterlab/apputils';
import { ILauncher } from '#jupyterlab/launcher';
import { requestAPI } from './handler';
import { ToolbarButton } from '#jupyterlab/apputils';
import { DocumentRegistry } from '#jupyterlab/docregistry';
import { INotebookModel, NotebookPanel } from '#jupyterlab/notebook';
import { IDisposable } from '#lumino/disposable';
import { Title, Widget } from '#lumino/widgets';
var nbPath: string; // Holds relative path of notebook to convert
// Create button on the toolbar
export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(app: JupyterFrontEnd) {
this.app = app;
}
readonly app: JupyterFrontEnd
// Create the toolbar button
createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
let mybutton = new ToolbarButton({
label: 'Measure Energy Usage',
onClick: async () => {
// Post request to Jupyter server containing relative
// path to .ipynb file
const dataToSend = { file: nbPath };
try {
const reply = await requestAPI<any>('hello', {
body: JSON.stringify(dataToSend),
method: 'POST'
});
console.log(reply);
} catch (reason) {
console.error(
`Error on POST /jlab-ext-example/hello ${dataToSend}.\n${reason}`
);
}
}
});
// Add the toolbar button to the notebook toolbar
panel.toolbar.insertItem(10, 'MeasureEnergyUsage', mybutton);
console.log("MeasEnerUsage activated");
// The ToolbarButton class implements `IDisposable`, so the
// button *is* the extension for the purposes of this method.
return mybutton;
}
}
/**
* Initialization data for the server-extension-example extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette],
activate: async (
app: JupyterFrontEnd
) => {
console.log('JupyterLab extension server-extension-example is activated!');
const your_button = new ButtonExtension(app);
app.docRegistry.addWidgetExtension('Notebook', your_button);
// Get name and relative path of active notebook tab
var shell = app.shell as ILabShell | IRetroShell;
// When user changes tabs, update nbPath to be the relative path for current notebook
const onTitleChanged = (title: Title<Widget>) => {
nbPath = title.caption;
nbPath = nbPath.slice(nbPath.indexOf("Path: ") + 6, nbPath.indexOf("Last Saved") - 1);
console.log(nbPath);
};
// Watch for user changing tabs in JupyterLab
shell.currentChanged.connect((_: any, change: any) => {
const { oldValue, newValue } = change;
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
handlers.py:
import os
import json
import subprocess
from notebook.base.handlers import APIHandler
from notebook.utils import url_path_join
import tornado
from tornado.web import StaticFileHandler
import measure_cell2
class RouteHandler(APIHandler):
# The following decorator should be present on all verb methods (head, get, post,
# patch, put, delete, options) to ensure only authorized user can request the
# Jupyter server
#tornado.web.authenticated
def get(self):
self.finish(json.dumps({"data": "At the /jlab-ext-example/hello endpoint; finding and converting notebook"}))
#tornado.web.authenticated
def post(self):
# receive .ipynb file name and relative path from index.ts on client-side
# input_data is a dictionary with a key "file"
input_data = self.get_json_body()
# convert notebook to .py file with nbconvert
subprocess.run(["jupyter", "nbconvert", input_data["file"], "--to", "script"])
# get name and absolute path of converted .py file
python_file_name = input_data["file"]
extension_index = python_file_name.find(".")
python_file_name = python_file_name[0:extension_index] + ".py"
abs_path = os.path.abspath(python_file_name)
print(abs_path)
# measure code energy usage
measure_cell2.measure(abs_path)
# confirm conversion and measurement occurred
data = {"greetings": "Converted notebook to the python file {}; now measuring energy usage".format(python_file_name)}
self.finish(json.dumps(data))
def setup_handlers(web_app, url_path):
host_pattern = ".*$"
base_url = web_app.settings["base_url"]
# Prepend the base_url so that it works in a JupyterHub setting
route_pattern = url_path_join(base_url, url_path, "hello")
handlers = [(route_pattern, RouteHandler)]
web_app.add_handlers(host_pattern, handlers)
# Prepend the base_url so that it works in a JupyterHub setting
doc_url = url_path_join(base_url, url_path, "public")
doc_dir = os.getenv(
"JLAB_SERVER_EXAMPLE_STATIC_DIR",
os.path.join(os.path.dirname(__file__), "public"),
)
handlers = [("{}/(.*)".format(doc_url), StaticFileHandler, {"path": doc_dir})]
web_app.add_handlers(".*$", handlers)
measure_cell2.py:
import requests
def measure(file_path):
base_url = 'http://localhost:9898'
# send file and get ID
url_id = base_url + '/id'
print(file_path)
files = {'file': open(file_path, 'rb')} # opens file into buffer; rb = read buffer
getID = requests.post(url_id, files=files)
ID = getID.json().get('id')
print("Running Code at ", file_path)
print(ID)
# send ID and get gpu results
url_results_gpu = base_url + '/results/gpu?id={}'.format(ID)
gpu_results = requests.get(url_results_gpu)
print(gpu_results.text)
# send ID and get cpu results
url_results_cpu = base_url + '/results/cpu?id={}'.format(ID)
cpu_results = requests.get(url_results_cpu)
print(cpu_results.text)

Related

INFO: Could not find files for the given pattern(s) - VSC and python

I've been following a tutorial to learn Python and smart contracts (I'm totally new to coding), and while following every step to the letter, VSCode keeps returning the following message >INFO: Could not find files for the given pattern(s).
Although it still returns whatever action I ask it to do:
from solcx import compile_standard, install_solc
import json
from web3 import Web3
import os
from dotenv import load_dotenv
load_dotenv()
install_solc("0.6.0")
with open("./SimpleStorage.sol", "r") as file:
simple_storage_file = file.read()
compiled_sol = compile_standard(
{
"language": "Solidity",
"sources": {"SimpleStorage.sol": {"content": simple_storage_file}},
"settings": {
"outputSelection": {
"*": {"*": ["abi", "metadata", "evm.bytecode", "evm.sourceMap"]}
}
},
},
solc_version="0.6.0",
)
with open("compiled_code.json", "w") as file:
json.dump(compiled_sol, file)
# get bytecode
bytecode = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["evm"][
"bytecode"
]["object"]
# get ABI
abi = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["abi"]
w3 = Web3(Web3.HTTPProvider("HTTP://127.0.0.1:7545"))
chain_id = 1337
my_address = "0x237d38135A752544a4980438c3dd9dFDe409Fb49"
private_key = os.getenv("PRIVATE_KEY")
# create the contract in python
SimpleStorage = w3.eth.contract(abi=abi, bytecode=bytecode)
# get the latest transaction
nonce = w3.eth.getTransactionCount(my_address)
# 1. build a transation
# 2. Sign a transation
# 3. Send a transation
transaction = SimpleStorage.constructor().buildTransaction(
{"chainId": chain_id, "from": my_address, "nonce": nonce})
signed_txn = w3.eth.account.sign_transaction(
transaction, private_key=private_key)
private_key = os.getenv("PRIVATE_KEY")
# Send the signed transaction
print("Deploying contract...")
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print("Deployed!")
# working with the contract
# contract address
# Contract ABI
simple_storage = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi)
# Call > simulate making the call and getting the return value, doesn't make a change on the blockchain
# Transact > actually makes a state change
# Initial value of favorite number
print(simple_storage.functions.retrieve().call())
print("Updating contract...")
store_transaction = simple_storage.functions.store(15).buildTransaction(
{"chainId": chain_id, "from": my_address, "nonce": nonce + 1}
)
signed_store_txn = w3.eth.account.sign_transaction(
store_transaction, private_key=private_key)
send_store_tx = w3.eth.send_raw_transaction(signed_store_txn.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(send_store_tx)
print("Updated!")
print(simple_storage.functions.retrieve().call())
And the result in the terminal is :
PS C:\Users\chret\Documents\demo\web3_py_simple_storage> python deploy.py
INFO: Could not find files for the given pattern(s).
Deploying contract...
Deployed!
0
Updating contract...
Updated!
15
So, I'm fairly confused, should I just ignore the warning "Could not find files for the given pattern(s)" ? Or is there anything I can do to fix it/is it going to create issues as I keep coding in those files? I've tried relocating the folders, including the path in Environment variables/PATH, but it doesn't stop this message from showing up.
It's been doing this from the beginning and nowhere does it show on the video I'm following (freecodecamp 16h video tutorial on youtube about blockchain).
Thank you!
you're importing solcx
during the import it runs solcx\install.py
near the end of that file it has this code
try:
# try to set the result of `which`/`where` as the default
_default_solc_binary = _get_which_solc()
except Exception:
# if not available, use the most recent solcx installed version
if get_installed_solc_versions():
set_solc_version(get_installed_solc_versions()[0], silent=True)
the _get_which_colc() function is defined earlier in the file, and runs this line (for windows)
response = subprocess.check_output(["where.exe", "solc"], encoding="utf8").strip()
which errors and sends the message you are worried about to the console
INFO: Could not find files for the given pattern(s).
This error is expected, and handled in the except Exception: clause (see above)
So nothing to worry about, you can ignore the warning :)
I too had this problem.
I wasn't able to fix it on my windows environment. But,
The github links to a tutorial to setup the brownie stack in an Ubuntu environment on Windows, and this has been working flawlessly for me. And it's easy to setup.
https://medium.com/#cromewar/how-to-setup-windows-10-11-for-smart-contract-development-and-brownie-e7d8d13555b3
It's not mentioned in the article, but currently (26/11/2021), you will want to install Node v16, and ganache v7.0.0-alpha.2 instead, due to compatibility issues.
Refer to link for NVM & node versions.
https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl
a smart contract man.sol, and it contains two(or one) contract in a file, like this:
pragma solidity ^0.8.0;
import "./SafeERC20.sol";
contract mainContract {
... (Any code can be here ...)
}contract childContract {
... (Other code here)}
and our python file. a.py:
import json
import os
import web3.eth
from web3 import Web3, HTTPProvider
from solcx import install_solc, set_solc_version,compile_standard
from dotenv import load_dotenv#here install solidity version
install_solc('v0.8.0')
set_solc_version('v0.8.0')
file_path = "."
name = "main.sol"
input = {
'language': 'Solidity',
'sources': {
name: {'urls': [file_path + "/" + name]}},
'settings': {
'outputSelection': {
'*': {
'*': ["abi", "metadata", "evm.bytecode", "evm.bytecode.sourceMap"],
},
'def': {name: ["abi", "evm.bytecode.opcodes"]},
}
}
}
output = compile_standard(input, allow_paths=file_path)
contracts = output["contracts"]
with open('compiled_code.json', "w") as file:
json.dump(output, file)
bytecode = contracts["SC-.sol"]["mainContract"]["evm"]["bytecode"]["object"]
abi = contracts["main.sol"]["mainContract"]["abi"]
# Deploy on local ganache# w3 = Web3(Web3.HTTPProvider("HTTP://127.0.0.1:7545"))
# chainId = 1337
# myAddress = "0x6235207DE426B0E3739529F1c53c14aaA271D..."
# privateKey = "0xdbe7f5a9c95ea2df023ad9......."
#Deploy on rinkeby infura rinkebyw3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/......"))
chainId = 4
myAddress = "0xBa842323C4747609CeCEd164d61896d2Cf4..."
privateKey ="0x99de2de028a52668d3e94a00d47c4500db0afed3fe8e40..."
SCOnline = w3.eth.contract(abi=abi, bytecode=bytecode)
nonce = w3.eth.getTransactionCount(myAddress)
transaction = SCOnline.constructor().buildTransaction({
"gasPrice": w3.eth.gas_price, "chainId": chainId, "from": myAddress, "nonce": nonce
})
signedTrx = w3.eth.account.sign_transaction(transaction, private_key= privateKey)
txHash = w3.eth.send_raw_transaction(signedTrx.rawTransaction)
txReceipt = w3.eth.wait_for_transaction_receipt(txHash)

Uncaught ReferenceError: require is not defined with EEL

I am Trying to run html page with electron + eel.
I have successfully loaded the webpage + eel.js.
My Problem is whenever I try to use require module in the javascript of the HTML page. it gives me the below:
Uncaught ReferenceError: require is not defined
The sequence is, launching the webapp using runner.py ( eel.start ), then electron start
Also, if I set mainWindow.loadFile('templates/index.html') in main.js file, instead of mainWindow.loadURL('http://localhost:8000/index.html'). the render just work fine and can handle electron window from main html javascript file. but eel is not loaded in this case.
If I tried the steps which in the guide. the electron html page opens normally with eel.js loaded up. but can not handle the electron window from html javascript file
runner.py
import eel
import eel.browsers
eel.init('templates')
eel.browsers.set_path('electron', 'node_modules/electron/dist/electron')
eel.start('index.html', mode='electron' , port=8000 ,host='localhost',disable_cache=True)
main.js:
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
enableRemoteModule: true
}
})
// and load the index.html of the app.
// mainWindow.loadFile('templates/index.html')
mainWindow.loadURL('http://localhost:8000/index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
html javascript:
function login_check(){
var serverIP = document.getElementById('serverIP').value
var Username = document.getElementById('usernameEntry').value
var Password = document.getElementById('passwordEntry').value
var RememberMe = document.getElementById('remember-me-checkbox').checked
if(serverIP != "" && Username != "" && Password != ""){
document.querySelector('.progress-bar-container-div').classList.add('active')
}
else{
const window = require("electron").getCurrentWindow()
alert("Required Fields are empty.")
document.querySelector('.progress-bar-container-div').classList.remove('active')
window.minimize();
}
}
package.json:
{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": [
"Electron",
"quick",
"start",
"tutorial",
"demo"
],
"author": "GitHub",
"license": "CC0-1.0",
"devDependencies": {
"electron": "^5.0.0"
}
}
error:

Downloading multiple instances of one image from a website and saving them in a Windows folder

I would like to download multiple images from thispersondoesnotexist.com and save them in a Windows folder. The site uses an AI StyleGAN to generate thousands of face images, but the problem is that the site only generates one image per view, which is labelled as image.jpg, and this single image changes every time the page is reset.
I would like to write a Python script that retrieves and saves multiple instances of this randomly generated image, ending up with a number of different images.
I tried using the following script written by Nandhugp:
import urllib.request
import random
n=input("How many images do you need?")
val=int(n)
dir=input("Enter the directory you want to save")
for i in range(val):
file_name = random.randrange(1,10000)
full_file_name = dir + str(file_name) + '.jpg' #Insert your
def downloader(image_url,full_file_name):
urllib.request.urlretrieve(image_url,full_file_name)
downloader("https://www.thispersondoesnotexist.com/",full_file_name)
However, the script doesn't work for me; I'm sorry but I'm new to Python 3 and am also having some difficulty understanding file paths in Windows. When the script asks for the directory I want to save the files in, do I enter "c:\faces\" or "c:/faces/"?
I'm using Win 7 64-bit OS on an older laptop.
# python3
import requests
def download(fileName):
f = open(fileName,'wb')
f.write(requests.get('https://thispersondoesnotexist.com/image', headers={'User-Agent': 'My User Agent 1.0'}).content)
f.close()
for i in range(2000):
download(str(i)+'.jpg')
//node js
var request = require('request');
var fs = require('fs');
var sleep = function (duration) {
return new Promise(resolve => {
setTimeout(() => resolve(), duration)
});
}
var downloadFile = function (url, fileName) {
return new Promise(resolve => {
var req = request(url);
var file = fs.createWriteStream(fileName);
req.pipe(file);
req.on('end', () => {
resolve();
})
})
}
var main = async function () {
for (var i = 0; i < 100; i++) {
console.log('Downloading ' + i)
await downloadFile('https://thispersondoesnotexist.com/image', `${i}.jpg`)
await sleep(1000);
}
}
main();
If you were using Linux or Cygwin on Windows, you could just run this:
watch -n6 wget https://thispersondoesnotexist.com/image

How to get Firefox Web Extension's "Internal UUID" from Selenium script?

I need to open moz-extension://internal-uuid page after my Selenium script is started to have an access to the extension's storage API, to set some prefs there, that this extension will read later and use to do some actions. But when I use selenium.webdriver.Firefox.add_addon(...) it returns the Extension ID that differs and can't be used to open the moz-extension:// page. Is there any way to get this Internal UUID from my code (not manually by inspecting about:debugging#addons). Or may be some way to pass the data I need from Selenium to Web Extension?
This code is working for me in Linux and Mac:
public static void main(String[] args) throws IOException {
FirefoxOptions options = new FirefoxOptions();
FirefoxDriver driver = new FirefoxDriver(options);
String userPrefsFileContent = readFile(driver.getCapabilities().getCapability("moz:profile") + "/prefs.js");
String extensionUuid = getExtensionUuid(userPrefsFileContent);
driver.quit();
}
private static String getExtensionUuid(String userPrefsFileContent) {
String uuid = null;
String[] usersPrefsList = userPrefsFileContent.split(";");
for (String currentPref : usersPrefsList) {
if (currentPref.contains("extensions.webextensions.uuids")) {
uuid = currentPref.split(":")[1].replaceAll("\"", "").replace("}", "")
.replace(")", "").replace("\\", "");
}
}
if(uuid.contains(",")) {
uuid = uuid.split(",")[0];
}
return uuid;
}
private static String readFile(String pathname) throws IOException {
File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int) file.length());
String lineSeparator = System.getProperty("line.separator");
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
fileContents.append(scanner.nextLine()).append(lineSeparator);
}
}
return fileContents.toString();
}
Don't know how, but I cannot get this approach to work in python, so instead found out another smart approach, instead of trying to get preference that is not provided by Firefox, you can set UUID to something with set-preference API. then just use it.
here is part of my code
if self.webdriver != None:
return self.webdriver
extensionPath = curPath+'/../../packages/firefox.xpi';
cap = DesiredCapabilities().FIREFOX
cap["marionette"]=True;
profile = webdriver.firefox.firefox_profile.FirefoxProfile();
profile.set_preference('extensions.webextensions.uuids',json.dumps({'support#ipburger.com':firefoxUUID}))
self.webdriver = webdriver.Firefox(firefox_binary=firefoxBinary,capabilities=cap,executable_path=curPath+'/../../drivers/geckodriver',firefox_profile=profile);
self.webdriver.install_addon(extensionPath,temporary=True);
return self.webdriver;
firefoxUUID is a string version of random UUID you generate
and you have to replace support#ipburger.com with your addon ID, which you can set inside manifest.json file
the code below is working for me in python on windows :
driver = webdriver.Firefox(service=firefox_service, options=firefox_options)
driver.install_addon(os.path.join(application_path, 'extension_firefox.xpi'), temporary=True)
time.sleep(1)
profile_path = driver.capabilities['moz:profile']
with open('{}/prefs.js'.format(profile_path), 'r') as file_prefs:
lines = file_prefs.readlines()
for line in lines:
if 'extensions.webextensions.uuids' in line:
sublines = line.split(',')
for subline in sublines:
if id_extension_firefox in subline:
internal_uuid = subline.split(':')[1][2:38]

How can I save prestashop invoices automatically and manually?

I want to print out an invoice(pdf) automatically, what's recently saved on the server. And also making manual saving possible
I'm using prestashop 1.6.1 and the invoices are mostly downloaded from the prestashop admin page, but I needed more easier way to print out these invoices, so I made an adminpage for myself it looks like this:
The printer button has a href of the invoice generated address
like:"http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230"
From the link I can download it and then print it when it's opened in pdf reader, but I want to do this in one click.
Soo... I made an script for automatically printing the pdf when its saved on some specific location
#! /usr/bin/python import os
import os
import time
import os.path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ExampleHandler(FileSystemEventHandler):
def on_created(self, event):
output=str(event.src_path.replace("./",""))
print(output)
#print event.src_path.replace("./","")
print "Got event for file %s" % event.src_path
os.system("lp -d HL2250DN %s" % output)
observer = Observer()
event_handler = ExampleHandler()
observer.schedule(event_handler, path='.',recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
There is two options to download it automatically to the server
1. Override PDF.php and PDFGenerator.php files like this:
PDF.php
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE)
parent::render('F', true);
return parent::render($display);
}
}
?>
PDFGenerator.php
<?php
class PDFGenerator extends PDFGeneratorCore
{
public function render($filename, $display = true)
{
if (empty($filename)) {
throw new PrestaShopException('Missing filename.');
}
$this->lastPage();
if ($display === true) {
$output = 'D';
} elseif ($display === false) {
$output = 'S';
} elseif ($display == 'D') {
$output = 'D';
} elseif ($display == 'S') {
$output = 'S';
} elseif ($display == 'F') {
$output = 'F';
$filename = '/folder/for/print_it/'.str_replace("#", "", $filename);
} else {
$output = 'I';
}
return $this->output($filename, $output);
}
}
?>
2. Use script to download
First attempt
The first option worked for automatic saving, but when I tried to save invoices manually I got an blank or broken pdf file. I also tried to change the pdf.php, but it dident work out for me. Also made an post about this: Prestashop saving invoices manually and automatically. No answers were given and I moved on second option.
Second attempt
I tried to download invoices with python script and it worked, but how can I know which one to download?
#!/usr/bin/env python
import requests
import webbrowser
url = "http://www.example.com/admin/index.php?controller=AdminLogin&token=5a01dc4e606bca6c26e95ddea92d3d15"
url2 = "http://www.example.com/admin/index.php?controller=AdminPdf&token=35b276c05aa6f5eb516737a8d534eb66&submitAction=generateInvoicePDF&id_order=3221"
payload = {'example': 'example',
'example': 'example',
'stay_logged_in':'2',
'submitLogin':'1',}
with requests.session() as s:
# fetch the login page
s.get(url)
# post to the login form
r = s.post(url, data=payload)
print(r.text)
response = s.get(url2)
with open('/tmp/metadataa.pdf', 'wb') as f:
f.write(response.content)
Soo the problem with this option is that.. How can I pass the href(what was clicked from the printer button) to url?
Solving this has been really frustrating and I know there is an simple and easy option for this, but I'm still looking for this.
Everytime you generate invoice PDF you are forcing it to be saved as local file.
What you want to do is add an extra GET parameter to the print button and check for its presence in the overriden class so that the PDF only gets stored as local file when you want to print directly.
So first add a GET parameter to print buttons eg. &print=1. Either in your template or wherever you are generating these buttons so that the button's href looks like this:
http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230&print=1
Now you can check if parameter exists in PDF class and only then force the PDF to be outputted to local file.
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE && Tools::getValue('print') == 1) {
// Output PDF to local file
parent::render('F');
// Redirect back to the same page so you don't get blank page
Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminMyController'));
}
else {
return parent::render($display);
}
}
}
You can keep the overriden PDFGenerator class as is.

Categories

Resources