Batch update failed: update results in the schema exceeding the page break limit - google-forms-api

I was trying to create an automatic form using the Forms API in python.
When I try to create more than 100 page breaks I came across the following error:
"HttpError 400 (...) returned "Batch update failed: update results in the schema exceeding the page break limit". Details: "Batch update failed: update results in the schema exceeding the page break limit".
The code I performed was the following:
from __future__ import print_function
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
import time
SCOPES = "https://www.googleapis.com/auth/forms.body"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
store = file.Storage('token.json')
creds = None
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
creds = tools.run_flow(flow, store)
form_service = discovery.build('forms', 'v1', http=creds.authorize(
Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
# Request body for creating a form
NEW_FORM = {
"info": {
"title": "TEST V0.0.1",
"documentTitle": "TEST V0.0.1",
}
}
BREAK_ITEM = {
"requests": [{
"createItem": {
"item":{
"pageBreakItem": {
},
},
"location": {
"index": 0
}
}
}]
}
# Creates the initial form
result = form_service.forms().create(body=NEW_FORM).execute()
for i in range(200):
question_setting = form_service.forms().batchUpdate(formId=result["formId"],body=BREAK_ITEM).execute()
print(i)
time.sleep(1)
# Prints the result to show the question has been added
get_result = form_service.forms().get(formId=result["formId"]).execute()
print(get_result)
If I change the number of times the cycle repeats (to under 100 times), the code works fine.
How can I overcome this?

Related

Not able to retrieve the spreadsheet id from workspace add-on

I'm developing a workspace add-on with alternate runtime; I configured the add-on to work with spreadsheets and I need to retrieve the spreadsheet id when the user opens the add-on. For test purposes I created a cloud function that contains the business logic.
My deployment.json file is the following:
{
"oauthScopes": ["https://www.googleapis.com/auth/spreadsheets.currentonly", "https://www.googleapis.com/auth/drive.file"],
"addOns": {
"common": {
"name": "My Spreadsheet Add-on",
"logoUrl": "https://cdn.icon-icons.com/icons2/2070/PNG/512/penguin_icon_126624.png"
},
"sheets": {
"homepageTrigger": {
"runFunction": "cloudFunctionUrl"
}
}
}
}
However, the request I receive seems to be empty and without the id of the spreadsheet in which I am, while I was expecting to have the spreadsheet id as per documentation
Is there anything else I need to configure?
The relevant code is quite easy, I'm just printing the request:
exports.getSpreadsheetId = function addonsHomePage (req, res) { console.log('called', req.method); console.log('body', req.body); res.send(createAction()); };
the information showed in the log is:
sheets: {}
Thank you
UPDATE It's a known issue of the engineering team, here you can find the ticket
The information around Workspace Add-ons is pretty new and the documentation is pretty sparse.
In case anyone else comes across this issue ... I solved it in python using CloudRun by creating a button that checks for for the object then if there is no object it requests access to the sheet in question.
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/', methods=['POST'])
def test_addon_homepage():
req_body = request.get_json()
sheet_info = req_body.get('sheets')
card = {
"action": {
"navigations": [
{
"pushCard": {
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": f"Hello {sheet_info.get('title','Auth Needed')}!"
}
}
]
}
]
}
}
]
}
}
if not sheet_info:
card = create_file_auth_button(card)
return card
def create_file_auth_button(self, card):
card['action']['navigations'][0]['pushCard']['fixedFooter'] = {
'primaryButton': {
'text': 'Authorize file access',
'onClick': {
'action': {
'function': 'https://example-cloudrun.a.run.app/authorize_sheet'
}
}
}
}
return card
#app.route('/authorize_sheet', methods=['POST'])
def authorize_sheet():
payload = {
'renderActions': {
'hostAppAction': {
'editorAction': {
'requestFileScopeForActiveDocument': {}
}
}
}
}
return payload

Messages in Django Channels sent outside consumer not being received

I'm trying to send messages to specific websocket instances, but neither channel_layer.send, nor using channel_layer.group_send with unique groups for each instance seems to be working, no errors are being raised, they just aren't received by the instances.
The function that sends the message is:
def listRequest(auth_user, city):
request_country = city["country_name"]
request_city = city["city"]
request_location = request_city +", "+request_country
concatenate_service_email = auth_user.service + "-" + auth_user.email
this_request = LoginRequest(service_and_email=concatenate_service_email, location=request_location)
this_request.generate_challenge()
this_request.set_expiry(timezone.now() + timezone.timedelta(minutes=5))
this_request.save()
channel_layer = get_channel_layer()
print(auth_user.current_socket)
async_to_sync(channel_layer.group_send)(
auth_user.current_socket,{
"type": "new.request",
"service_and_email" : concatenate_service_email
},
)
My current working consumers.py (receive and scanrequest don't have anything that's likely to be relevant to the issue):
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from .helpers import verify_identity, unique_group
from django.utils import timezone
from .models import Authentication, LoginRequest
import json
import time
class AuthConsumer(WebsocketConsumer):
account_list =[]
def connect(self):
print("Connect attempted")
print(self.channel_name)
print(unique_group(self.channel_name))
async_to_sync(self.channel_layer.group_add)(unique_group(self.channel_name), self.channel_name)
self.accept()
def disconnect(self, close_code):
print("Disconnect attempted")
async_to_sync(self.channel_layer.group_discard)(unique_group(self.channel_name), self.channel_name)
for i in self.account_list:
serviceEmailSplit = i.split("-")
try:
auth_user = Authentication.objects.get(service=serviceEmailSplit[0],email=serviceEmailSplit[1])
auth_user.set_socket("NONE")
auth_user.save()
except:
print("Error user %s does not exist" %i)
pass
def receive(self, text_data):
print("Receiving data")
if text_data[0:7] == "APPROVE":
data_as_list = text_data.split(",")
serviceEmailSplit = data_as_list[1].split("-")
auth_user = Authentication.objects.get(service=serviceEmailSplit[0],email=serviceEmailSplit[1])
this_request = LoginRequest.objects.get(service_and_email=data_as_list[1],approved=False, expiry__gt=timezone.now())
if verify_identity(auth_user.public_key, data_as_list[2], this_request.challenge):
this_request.set_approved()
self.send("Request Approved!")
else:
self.send("ERROR: User verification failed")
else:
self.account_list = text_data.split(",")
self.account_list.pop(-1)
print(self.account_list)
for i in self.account_list:
serviceEmailSplit = i.split("-")
try:
auth_user = Authentication.objects.get(service=serviceEmailSplit[0],email=serviceEmailSplit[1])
auth_user.set_socket(unique_group(self.channel_name))
auth_user.save()
except:
self.send("Error user %s does not exist" %i)
self.scanRequest()
def scanRequest(self):
requestSet = LoginRequest.objects.filter(service_and_email__in = self.account_list, approved = False, request_expiry__gt = timezone.now())
if requestSet.count() > 0:
for request in requestSet:
self.send(request.service_and_email+","+request.location+","+str(request.challenge))
else:
self.send("NOREQUESTS")
def new_request(self,event):
print("NEW REQUEST!")
this_request = LoginRequest.objects.filter(service_and_email = event["service_and_email"]).latest('request_expiry')
self.send(this_request.service_and_email+","+this_request.location+","+str(this_request.challenge))
And my routing.py:
from django.urls import re_path
from . import consumers
from django.conf.urls import url
websocket_urlpatterns = [
url(r"^ws/$", consumers.AuthConsumer.as_asgi()),
]
"NEW REQUEST!" is never printed, having tried to call it both by sending a message directly, and neither does using groups like I have written above.
My redis server appears to be working from testing like the documentation for the channels tutorial suggests:
https://channels.readthedocs.io/en/stable/tutorial/part_2.html
I'm pretty stumped after attempts to fix it, and I've looked at the other posts on stackoverflow with the same/similar issues and I'm already following whatever solutions they have in my code.

I was a bad boy: Firefox addon to edit body of post request (which I am doing manually atm)

I need to intercept POST request, change a parameter and let it continue in Mozilla addon.
Background:
I am part of the comment section of example.org. That site had an option in profile to allow to show 10, 25, 50, 100 and 500 comments per page. A week ago, in order to save bandwidth, they removed that option and locked the users to 50 comments per page or less.
I was a naughty boy and researched a bit.
There is https://example.org/api.html?GET_COMMENTS post method.
As part of a JSON object in the body of request, it takes preferred_count parameter. The object looks something like this
{ userid: 1234567,
postId: 56789,
preferred_count: 50,
location_parameters:[] etc}
My research lead me to a discovery that if I change preferred_count to 500 in the request body in Firefox developer tools then resend the request I will get full 500 comments on that post as a response! Neat. But it sucks to be doing it constantly. So I tried to develop a firefox addon to do it for me.
My manifest.json looks like this:
{
"description": "Makes example comments.cool.",
"manifest_version": 2,
"name": "examplecomments",
"version": "1.0",
"permissions": [
"webRequest",
"webRequestBlocking",
"storage",
"https://example.com/*",
"https://example.org/api.html?GET_COMMENTS"
],
"icons": {
"48": "border.png",
"96": "border.png"
},
"applications": {
"gecko": {
"id": "borderify#example.com"
}
},
"background": {
"scripts": [ "badComments.js" ]
} }
My badComments.js looks like this:
var lookUrl = "https://example.com/api.phtml?GET_COMMENTS";
function moreComments(requestResp) {
var dec = new TextDecoder();
var enc = new TextEncoder();
if (requestResp.url.toLowerCase() == lookUrl.toLowerCase()) {
console.log(requestResp);
var rawBytes = requestResp.requestBody.raw[0].bytes;
var decoded = dec.decode(rawBytes)
console.log(decoded);
var requestedObject = JSON.parse(decoded);
var numberOnPage = requestedObject.body[1].server_get_comments.preferred_count;
console.log(numberOnPage);
numberOnPage = 500;
console.log(numberOnPage);
requestedObject.body[1].server_get_comments.preferred_count = numberOnPage;
console.log( requestedObject.body[1].server_get_comments.preferred_count);
var requestedObjString = JSON.stringify(requestedObject);
console.log(requestedObjString);
var encodedObject = enc.encode(requestedObjString);
console.log(encodedObject);
requestResp.requestBody.raw[0].bytes = encodedObject.buffer;
console.log(requestResp);
}
return {requestBody:requestResp.requestBody};
// return {requestBody:requestResp};
}
browser.webRequest.onBeforeRequest.addListener(
moreComments,
{ urls: [lookUrl] },
["blocking", "requestBody"]
);
Console shows that preferred_count gets replaced with the correct number. But after scanning it in firefox console doesn't show it, it remains the old one! And I never get my 500 comments. What am I doing wrong? How can I change request, or, failing that, stop the existing one, copy all the needed data for request and send my own?
thank you.

How to order portable storage using SoftLayer API

Is there a simple method to order portable storage given the input datacenter such as WDC06 and size 500 GB.
At the moment the method I know of is painful, complex and manual, if I have do this in a new datacenter. First get the configuration through Product_Package and then going through long list of items to find the right product id, itemId ... etc. This call also requires that I should know the pkgid before hand.
categories = client['Product_Package'].getConfiguration(id=pkgId, mask='isRequired, itemCategory.id, itemCategory.name, itemCategory.categoryCode')
Please if you can share some code samples if this ordering process can be simplified.
I have not idea how you are ordering the portable storage,but you need to use the placeOrder method and get the proper prices for the disk size that you want to order, this literature can help you to understand how to make orders:
https://sldn.softlayer.com/blog/cmporter/location-based-pricing-and-you
https://sldn.softlayer.com/blog/bpotter/going-further-softlayer-api-python-client-part-3
The process to pick the correct prices is hard, but you can use the object filters to get them:
https://sldn.softlayer.com/article/object-filters
and here a sample using the softlayer Python client:
import SoftLayer
# Your SoftLayer API username and key.
API_USERNAME = 'set me'
API_KEY = 'set me'
datacenter = "wdc06" # lower case
size = "500" # the size of the disk
diskDescription = "optional value"
client = SoftLayer.Client(username=API_USERNAME, api_key=API_KEY)
package = 198 # this package is always the same
# Using a filter to get the price for an especific disk size
# into an specific datacenter
filter = {
"itemPrices": {
"pricingLocationGroup": {
"locations": {
"name": {
"operation": datacenter
}
}
},
"item": {
"capacity": {
"operation": size
}
}
}
}
price = client['SoftLayer_Product_Package'].getItemPrices(id=package, filter=filter)
# In case the request do not return any price we will look for the standard price
if not price:
filter = {
"itemPrices": {
"locationGroupId": {
"operation": "is null"
},
"item": {
"capacity": {
"operation": size
}
}
}
}
price = client['SoftLayer_Product_Package'].getItemPrices(id=package, filter=filter)
if not price:
print ("there is no a price for the selected datacenter %s and disk size %s" % (datacenter, size))
sys.exit(0)
# getting the locationId for the order template
filter = {
"regions": {
"location": {
"location": {
"name": {
"operation": datacenter
}
}
}
}
}
location = client['SoftLayer_Product_Package'].getRegions(id=package, filter=filter)
# now we are creating the ordertemplate
orderTemplate = {
"complexType": "SoftLayer_Container_Product_Order_Virtual_Disk_Image",
"packageId": package,
"location": location[0]["location"]["location"]["id"],
"prices": [{"id": price[0]["id"]}],
"diskDescription": diskDescription
}
#When you are ready to order change "verifyOrder" by "placeOrder"
order = client['SoftLayer_Product_Order'].verifyOrder(orderTemplate)
print order

JIRA do I have a way to get the list all ID of my transition steps?

I want to synchronize between two systems. However, to update the transition status of the bug I have to send a JSON file with my arguments (new status) something like this:
{
"update": {
"comment": [
{
"add": {
"body": "Comment added when resolving issue"
}
}
]
},
"transition": {
"id": "5"
}
}
To set a new status I have to set it's id, How can I get the list of all the IDs and the description of each one.
You can get a list of the transitions possible for this issue by the current user, along with fields that are required and their types by url /rest/api/2/issue/{issueIdOrKey}/transitions (get request)
You can use the following python script to get the information you want.
#!/usr/bin/env python
from __future__ import print_function
import ConfigParser
import requests
import json
import base64
import sys
def print_error(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def get_issue(user,password,search_url):
user_auth = base64.b64encode(user+':'+password)
headers = {'Authorization': 'Basic ' + user_auth}
return requests.get(search_url, headers=headers)
def main():
if len(sys.argv) < 2:
usage_message = 'Usage: ' + sys.argv[0] + ' issue_number'
print_error(usage_message)
sys.exit(1)
config = ConfigParser.RawConfigParser()
config.read('config.properties')
jira_user = config.get('Global', 'jira_user')
jira_pass = config.get('Global', 'jira_pass')
jira_base_url = config.get('Global', 'jira_base_url')
issue_url = config.get('Global', 'issue_url')
issue = sys.argv[1]
issue_search_url = jira_base_url + issue_url + issue + '/transitions'
response = get_issue(jira_user,jira_pass,issue_search_url)
if response.status_code == 404:
print_error(issue + ' NOT FOUND!')
sys.exit(1)
data = response.json()
for transition in data['transitions']:
print("%s %s" % (transition['id'], transition['name']))
main()
You need to have a configuration file (config.properties) in the same directory as the script with the following content:
[Global]
jira_user=username
jira_pass=pass
jira_base_url=http://your_jira_url.com
issue_url=/rest/api/2/issue/
Then you call the script like this:
./get_transitions.py your_ticket_number

Resources