Python - For Loop not iterating through multiple instances of a dictionary - python

I have the following code
def generate_matter(leaver_user,vaultAccessToken):
for user in leaver_user:
url = "https://vault.googleapis.com/v1/matters/"
headers = {
"Accept" : "application/json",
"Content-Type" : "application/json",
"Authorization": "Bearer " + vaultAccessToken
}
body = json.dumps ({
"state": "OPEN",
"description": "Generated by Python",
"name": user + "'s archive"
})
response = requests.request(
"POST",
url,
headers=headers,
data=body
)
jsonContent = json.loads(response.text)
matterID=jsonContent["matterId"]
#print("Matter ID for " + user + " is " + matterID)
#print(jsonContent)
matter={
"matterInstance": {
"user": user,
"userInfo": {
"matterID": matterID
}
}
}
return matter
def generate_search_query(matter,leaver_user,vaultAccessToken):
print(matter)
for key, value in matter.items():
user=(matter['matterInstance']['user'])
matterID=(matter['matterInstance']['userInfo']['matterID'])
url = "https://vault.googleapis.com/v1/matters/"+matterID+"/savedQueries"
headers = {
"Accept" : "application/json",
"Content-Type" : "application/json",
"Authorization": "Bearer " + vaultAccessToken
}
body=json.dumps({
"displayName": user + "'s email search query",
"query": {
"corpus": "MAIL",
"dataScope": "ALL_DATA",
"searchMethod": "ACCOUNT",
"accountInfo": { "emails": [user]},
"mailOptions": {"excludeDrafts" : "false"},
"timeZone": "Atlantic/Canary",
"method": "ACCOUNT"
}}
)
response = requests.request(
"POST",
url,
headers=headers,
data=body
)
jsonContent = json.loads(response.text)
print(matterID)
print(body)
print(jsonContent)
savedQueryID=jsonContent["savedQueryId"]
print("savedQueryId for " + user + " is " + savedQueryID + " matterID is " + matterID)
matter={
"matterInstance": {
"user": user,
"userInfo": {
"matterID": matterID,
"savedQueryID": savedQueryID
}
}
}
return matter
matter=generate_matter(leaver_user,vaultAccessToken)
savedQueryID=generate_search_query(matter,leaver_user,vaultAccessToken)
What works is the first function - generate_matter().
This returns multiple instances of matter such as
{'matterInstance': {'user': 'testing.testing#domain.com', 'userInfo': {'matterID': '12-34-56-78-91'}}}
{'matterInstance': {'user': 'adtesting#domain.com', 'userInfo': {'matterID': '12-34-56-78-99'}}}
However the function generate_search_query() only seems to execute on the first instance of matter.
I've confirmed this by printing the matter in generate_search_query() before the for loop executes and only the first instance of matter is returned.
{'matterInstance': {'user': 'testing.testing#domain.com', 'userInfo': {'matterID': '12-34-56-78-91'}}}
Adding from the below comments as its useful information.
Printing matter within the for loop from generate_matter does return multiple instances of matter.
Printing matter immediately before calling savedQueryID=generate_search_query(matter,leaver_user,vaultAccessToken) only returns a single instance of matter, so this is when i print / call it outside of the function
How would I solve this so that multiple instances of matter are executed in the for loop within generate_search_query() ?
Thanks

At the end of generate_matter() you're overwriting matter with the last iteration, and then returning it, so its only returning a single element.
To fix this, create a list at the start of generate_matter() (matterList = []) and then where you have matter={...} in generate_matter() replace it with matterList.append({...}). Then at the end of the function return matterList instead of matter.
In generate_search_query() you'll need to wrap everything in another for loop to loop through the list.

Related

How do i use the "next" url for post request?

So how does python call the "next" page in a post request?
I know what i neeed to do, but not sure how to implement, all the examples in youtube use a # and not a cursor, being a semi beginner i am a bit confused
This is my code so far:
def main_request(headers, url1, params):
response = requests.post(url1, headers=headers, json=params, verify=False)
jsonData = response.json()
has_next_key = False
nextKey = ""
if "next_key" in jsonData:
next = True
nextKey = jsonData["next"]
while has_next_key:
data = {"limit_count":500, "limit_size":10000,"curr_key":nextKey}
params = {"data":json.dumps(data, separators=(",", ":"))}
req = requests.post(url1, headers=headers, json=params, verify=False) ## this should do GET request for the third page and so on...
if "next_key" in req:
nextKey = req["next_key"]
print(nextKey) # this returns "3321" which is the value for "next_key" in second page
else:
has_next_key = False
# no next_key, stop the loop
This is the value is brings back at the end of each request
{
"data": [],
"metadata": {},
"links": [
{
"href": "https://us.api.insight.rapid7.com:443/vm/v4/integration/assets?page=0&size=2",
"rel": "first"
},
{
"href": "https://us.api.insight.rapid7.com:443/vm/v4/integration/assets?page=0&size=2",
"rel": "self"
},
{
"href": "https://us.api.insight.rapid7.com:443/vm/v4/integration/assets?page=1&size=2&cursor=1542252837:::_S:::12474375-34a7-40a3-9821-28db0b5cc90e-default-asset-10",
"rel": "next"
},
{
"href": "https://us.api.insight.rapid7.com:443/vm/v4/integration/assets?page=1097&size=2",
"rel": "last"
}
]
}
according to rapid7 support, i need to use the cursor value
Given your jsonData as input, you can use this code to get the next url and assign it to url1:
for item in jsonData.get("links", []):
if item["rel"] == "next":
url1 = item["href"]
break
This only finds the first url. If you need all urls, I'd recommend adding all urls to a list.
For examples:
links = [item["href"] for item in jsonData.get("links", []) if item["rel"] == "next"]

How do i get my visitor counter in my code to show up on the client side or how do i get my value to become an integer

My code's purpose is to reach into a database and increment the value of the counter by 1 and while my code does that I am having issues displaying this data to the client side. i am not able to just json.dumps my response variable because dynamodb automatically turns my value into a decimal for some reason. I was able to get it to print using responseBody = json.dumps({"ID": int(response["Attributes"]["Counter"])}) however it is showing up on the webpage with {"ID": "x"} I want just the X value which is being incremented and not anything else. does anyone know how I can do this? It would be much appreciated. the entirety of my python code is below.
import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Visitors')
Key = {"ID": {"0"}}
def lambda_handler (event, context):
response = table.update_item(
Key={
"ID": 0
},
ExpressionAttributeNames = {
"#c": "Counter"
},
UpdateExpression= "set #c = #c + :val",
ExpressionAttributeValues={
":val": 1
},
ReturnValues= "UPDATED_NEW"
)
responseBody = json.dumps({"ID": int(response["Attributes"]["Counter"])})
return {
"statusCode": 200,
"headers": {
'Access-Control-Allow-Headers': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
},
'body': (responseBody)
}
You are receiving {"ID": "x"} because that's what you are writing into the body. If you only want to return the number, you can change it to
responseBody = response["Attributes"]["Counter"]
return {
"statusCode": 200,
"headers": {
'Access-Control-Allow-Headers': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
},
'body': responseBody
}
Potentially, you'd need to convert it to a string, or do other adjustments, based on what exactly response["Attributes"]["Counter"] returns you.
The essence is, that you get exactly what you put into the body attribute. So if you don't want to have "ID": in there, just leave it out.
Just return the response["Attributes"]["Counter"] as the responseBody value and then pass that into tour body within the return statement. You can alter the value into a string or integer or whatever you need before returning it if you need to.

Python's request() returning response 400 when trying to get file from API

This is my first time messing with APIs. I wrote some code to get data from USASpending's API using a 'GET' call and it works. I'm now trying to get data from another endpoint that only has 'post' capability. The code below returns the '400' response. I'm not sure what I need to change to get the output to be produced. I don't know if it matters but this endpoint produces a zip file.
import requests
payload = {"award_levels":["prime_awards"],"filters":{"award_types":["contracts","direct_payments","grants","idvs","loans","other_financial_assistance"],"agency":"United States Mint","date_type":"action_date","date_range":{"start_date":"2019-01-01","end_date":"2019-01-31"}},"columns":[],"file_format":"csv"}
response = requests.post('https://api.usaspending.gov/api/v2/bulk_download/awards/', params = payload).json()
Thanks in advance
Update:
This is what I finally used. I have the date as dynamic so I can automate this pull monthly using task scheduler. If you want to pull a specific date, remove the date variable reference in the header declaration and run.
pl_str1 = """{
"filters": {
"prime_award_types": [
"A",
"B",
"C",
"D",
"IDV_A",
"IDV_B",
"IDV_B_A",
"IDV_B_B",
"IDV_B_C",
"IDV_C",
"IDV_D",
"IDV_E",
"02",
"03",
"04",
"05",
"10",
"06",
"07",
"08",
"09",
"11"],
"agency": 54,
"date_type": "action_date","""
# Inserting date_range variable into API call
pl_str2 = '"date_range": {"start_date":' + date_3Months_prior +', "end_date":' + date_today + '}'
pl_str3 = """},
"columns": [],
"file_format": "csv"}"""
desired_payload = pl_str1 + pl_str2 + pl_str3
# $$$$$$$$$$$$$$$$$$$$$$$$$$$ REQUESTING DESIRED INFO FROM THE API HERE $$$$$$
url = 'https://api.usaspending.gov/api/v2/bulk_download/awards/'
headers = {'Content-Type': 'application/json'}
resp = requests.post(url, headers=headers, data=desired_payload)
if resp.status_code == 200:
print('success')
print(resp.content)
else:
print('fail')
# API returns a zip file; grabbing that
# This will turn the API response into a string I can use regex on
test = resp.content.decode('UTF-8')
# Extracting url for zip we want to retrieve
test2 = re.findall(r"file_url\S+\.zip", test)[0]
test3 = re.findall(r"https\S+\.zip", test2)[0]
import zipfile
import io
import time
r = requests.get(test3)
# add sleep in case it takes a while for the API to return stuff; not sure if
# but just in case
time.sleep(5)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall()
params are the query parameters in the URL.
e.g
www.stackoverflow.com?parameter=test
This can be expressed as
payload = {
"parameter": "test"
}
POST request has a body, This is the same data that would've been sent if you were posting from a form, You're sending a body, You have some parameters in requests module function .post that deal with the body, You can either use data=payload or json=payload, See the official documentation on this.
When you run this url (https://api.usaspending.gov/api/v2/bulk_download/awards/) in browser and fill form with your request. You will get respons like this
{
"detail": "Missing one or more required body parameters: prime_award_types or sub_award_types"
}
Add fliters, data_range, data_type , agency,prime_award_types
Your request should be like this:
{
"filters": {
"date_range": {
"start_date": "2019-01-01",
"end_date": "2019-12-31"
},
"date_type": "action_date",
"agency": 50,
"prime_award_types": [
"02",
"03",
"04",
"05",
"A",
"B",
"C",
"D"
],
"award_levels": [
"prime_awards"
],
"filters": {
"award_types": [
"contracts",
"direct_payments",
"grants",
"idvs",
"loans",
"other_financial_assistance"
],
"agency": "United States Mint",
"date_type": "action_date",
"date_range": {
"start_date": "2019-01-01",
"end_date": "2019-01-31"
}
},
"columns": [],
"file_format": "csv"
}
}
Get form data in function and send it an other function with request.
import requests
from flask import Flask, return , request,
#videos.route("/ajaxprocess", methods=["GET","POST"])
def ajaxprocess():
if request.method =="POST":
text = request.form.get('text_text')
font = request.form.get('font_text')
color = request.form.get('color_text')
start_text = request.form.get('start_text')
end_text = request.form.get('end_text')
video_id = request.form.get('vid')
all_data = {'status':'OK','text':text,'font':font,'color':color,'start_text':start_text,'end_text':end_text,'vid':video_id}
r = requests.post("http://127.0.0.1:5000/videos/test_text",json=all_data)
print(r)
return redirect(url_for("videos.show_videos"))
#videos.route("/test_text", methods = ['POST'])
def test_text():
data = request.get_json("")
print(data)
return "success!"

Opsgenie powershell alert post not working

I have successfully made an alert post using Python, but cannot get my powershell alert creation to work. I just get a wall of HTML in my response and no alert creation. Message is the only required field.
Here's what I'm using and it does not work
$api = "XXX"
$URI = "https://api.opsgenie.com/v2/alerts"
$head = #{"Authorization" = "GenieKey $api"}
$body = #{
message = "testing";
responders =
]#{
name = "TEAMNAMEHERE";
type = "team"
}]
} | ConvertTo-Json
$request = Invoke-RestMethod -Uri $URI -Method Post -Headers $head -ContentType "application/json" -Body $body
$request
Here is my python code I made and it works just fine.
import requests
import json
def CreateOpsGenieAlert(api_token):
header = {
"Authorization": "GenieKey " + api_token,
"Content-Type": "application/json"
}
body = json.dumps({"message": "testing",
"responders": [
{
"name": "TEAMNAMEHERE",
"type": "team"
}
]
}
)
try:
response = requests.post("https://api.opsgenie.com/v2/alerts",
headers=header,
data=body)
jsontemp = json.loads(response.text)
print(jsontemp)
if response.status_code == 202:
return response
except:
print('error')
print(response)
CreateOpsGenieAlert(api_token="XXX")
EDIT: So I've figured out it has something to do with my "responders" section. It has something to do with the [ ]...but I haven't been able to figure out what exactly. If I remove them, it wont work. If I turn the first one around, it won't work. I can get the alert to create successfully, however I keep getting the following error:
] : The term ']' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At \\file\Tech\user\powershell scripts\.not working\OpsGenieAlert.ps1:7 char:17
+ ]#{
+ ~
+ CategoryInfo : ObjectNotFound: (]:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
You need to convert your $body to JSON
$api = "XXX"
$URI = "https://api.opsgenie.com/v2/alerts"
# Declare an empty array
$responders = #()
# Add a new item to the array
$responders += #{
name = "TEAMNAMEHERE1"
type = "team1"
}
$responders += #{
name = "TEAMNAMEHERE2"
type = "team2"
}
$body = #{
message = "testing"
responders = $responders
} | ConvertTo-Json
$invokeRestMethodParams = #{
'Headers' = #{
"Authorization" = "GenieKey $api"
}
'Uri' = $URI
'ContentType' = 'application/json'
'Body' = $body
'Method' = 'Post'
}
$request = Invoke-RestMethod #invokeRestMethodParams

"Errors": ["Cannot parse input stream due to I/O error as JSON document: Parse error: expected '}' but saw ',' [ chars read = *****]

I'm trying to create defects programmatically. I am getting a couple errors and having trouble getting any further. Here, essentially, is the code:
import requests, json
rally_auth = ('**uid', '***pwd')
rally_auth_url = 'https://rally1.rallydev.com/slm/webservice/v2.0/security/authorize'
rally_defect = 'https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement'
workspace_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/workspace/123***'
fe_project_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/project/134***'
user_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/user/106***'
l2_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/portfolioitem/l2roadmapitem/166***'
headers = {"Accept": "application/json", "Content-Type": "application/json", "ZSESSIONID" : "_iv********"}
s = requests.Session()
token = '_iv**********'
url = rally_defect + '/create?key=' + token
payload = {
'Workspace' : workspace_ref,
'Name': 'Tesing',
'Description': 'Testing',
'Project': fe_project_ref,
'StoryType': "New Feature",
'PortfolioItem' : l2_ref,
'Owner' : user_ref,
'ScheduleState':'Defined',
}
r = s.put(url, data=json.dumps(payload), headers=headers)
print r.text
print r.status_code
{"CreateResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": ["Cannot parse input stream due to I/O error as JSON document: Parse error: expected '}' but saw ',' [ chars read = *****], "Warnings": []}}
You will need to provide the Artifact type in your JSON. Below is an update to your code that should work for you. I am also assuming 'StoryType' is a Custom String Field. You will need to update the name to 'c_StoryType' to add a value to a Custom Field.
I also removed some of the extra lines. Since you are using an API Key and setting it as the ZSessionID in the Headers, you will not need the Security Token to create the Artifact.
import requests, json
rally_defect = 'https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement'
workspace_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/workspace/123***'
fe_project_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/project/134***'
user_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/user/106***'
l2_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/portfolioitem/l2roadmapitem/166***'
headers = {"Accept": "application/json", "Content-Type": "application/json", "ZSESSIONID" : "_iv********"}
s = requests.Session()
url = rally_defect + '/create'
payload = {
"HierarchicalRequirement" : {
"Workspace" : workspace_ref,
"Name" : "Tesing",
"Description" : "Testing",
"Project" : fe_project_ref,
"c_StoryType" : "New Feature",
"PortfolioItem" : l2_ref,
"Owner" : user_ref,
"ScheduleState" : "Defined"
}
}
r = s.put(url, data=json.dumps(payload), headers=headers)
print r.text
print r.status_code

Categories

Resources