Python - Mailchimp Batch PUT requests - python

I'm trying to use the batch functionality for the Mailchimp API. My current set up is like this
operations = []
for idx, row in users_df.iterows():
payload = {
'email': row['email'],
'last_updated': row['new_time'],
'custom_value': row['new_value']
}
operation_item = {
"method": "POST", # I changed this to PUT
"path": '/lists/members/12345',
"body": json.dumps(payload),
}
operations.append(operation_item)
client = mc.MailChimp(MAILCHIMP_TOKEN, MAILCHIMP_USER)
batch = client.batches.create(data={"operations": operations})
Whenever I use the POST method I get this error: old_user#gmail.com is already a list member. Use PUT to insert or update list members.
But whenever I change my method to PUT, I get this other error: The requested method and resource are not compatible. See the Allow header for this resource's available methods.
Is there a way to overcome this? I have already looked at this and this is a similar problem in Ruby.

you can't do PUT to the list resource "/lists/members/12345", you need to change path to be "/lists/members/12345/{email}"
this code works for us:
def add_users_to_mailchimp_list(list_id, users):
operations = []
client = get_mailchimp_client()
for user in users:
member = {
'email_address': user.email,
'status_if_new': 'subscribed',
'merge_fields': {
'FNAME': user.first_name or '',
'LNAME': user.last_name or '',
},
}
operation_item = {
"method": "PUT",
"path": client.lists.members._build_path(list_id, 'members', user.email),
"body": json.dumps(member),
}
operations.append(operation_item)
return client.batches.create(data={"operations": operations})
using protected method client.lists.members._build_path is a bit hacky I guess, if you like you can build the url manually, it will be f'lists/{list_id}/members/{user.email}'

Related

'InvalidRegistration' FCM when sending Push Notifications via Appium and Python

I'm getting 'InvalidRegistration' error when I try to send a push notification to my Android device.
Header:
headers = {
'Content-Type': 'application/json',
'Authorization': 'key=' + serverToken,
{
Body:
body = {
"to": deviceToken,
"notification": {
"body": "Welcome to blabla",
"title": "Blabla trully loves you, did you know that?",
"priority": "high"
}
Response:
200
{'multicast_id': 6053848281333651847, 'success': 0, 'failure': 1, 'canonical_ids': 0, 'results': [{'error': 'NotRegistered'}]}
The idea is that I'm using Appium method driver.get_clipboard_text() to get a token which is already copied in device clipboard and store it in the following variable:
deviceToken = self.driver.get_clipboard_text()
Which I pass it to my JSON. Also, if I manually store the token in my variable it will successfully work and get the push notification on my device.
I've tried to use several formatting python types by using another variable where i store a previous one where I do call that method I mentioned from Appium, but without success.
Any thoughts?

Convert Kibana query (create index pattern) to Python request

I'm trying to convert this Kibana query to Python:
PUT /.kibana/_doc/index-pattern:tempindex
{
"type": "index-pattern",
"index-pattern": {
"title": "tempindex",
"timeFieldName": "sendTime"
}
}
This is what I have so far:
HEADERS = {
'Content-Type': 'application/json'
}
uri = "http://localhost:5601/_doc/index-pattern:tempindex"
query = json.dumps({
"type": "index-pattern",
"index-pattern": {
"title": "tempindex",
"timeFieldName": "sendTime"
}
})
r = requests.put(uri, headers=HEADERS, data=query).json()
print(r)
But it gives me
{'statusCode': 404, 'error': 'Not Found', 'message': 'Not Found'}
What am I doing wrong?
P.S: Both Elastic and Kibana servers are local (Windows 10).
Seems that just changing the uri does the trick:
uri = "http://localhost:9200/.kibana/_doc/index-pattern:tempindex"
But I'm not sure about the HEADERS, cuz as lupanoide pointed out, kbn-xsrf: true should be present, but either way it seems to be working and apparently the results are the same (I haven't spotted a difference yet).
Edit: As the doc says:
kbn-xsrf: true
By default, you must use kbn-xsrf for all API calls, except in the
following scenarios:
The API endpoint uses the GET or HEAD operations
The path is whitelisted using the server.xsrf.whitelist setting
XSRF protections are disabled using the server.xsrf.disableProtection setting
So I think it should be present.

getChanges Sharepoint rest API

I am using Sharepoint 2013 REST api to find out the incremental changes that have happened in the root site. My request is like below:
headers = {"Authorization": 'Bearer ' + access_token, "accept": "application/json", "odata": "verbose"}
headers["content-type"] = "application/json;odata=verbose"
body = { 'query': { '__metadata': { 'type': 'SP.ChangeQuery' },'Web': True, 'Update': True, 'Add': True,
'ChangeTokenStart':{'__metadata':{'type':'SP.ChangeToken'},
'StringValue': '1;1;5b9752ee-f410-4cc6-9ab6-eb18c2ad802f;636252579049500000;89866182'}
}
}
In response I am getting lot of changerequest objects. One of them is as below:
{
'odata.type': 'SP.ChangeWeb',
'ChangeToken': {
'StringValue': '1;1;5b9752ee-f410-4cc6-9ab6-eb18c2ad802f;636252779425600000;89976872'
},
'WebId': '6e21eadd-4155-494d-9a8e-1046865bdd4b',
'ChangeType': 2,
'odata.id': 'https://<site url>/_api/SP.ChangeWeb87f1a9c6-937b-4507-973d-fc2d1b949aed',
'SiteId': '5b9752ee-f410-4cc6-9ab6-eb18c2ad802f',
'odata.editLink': 'SP.ChangeWeb87f1a9c6-937b-4507-973d-fc2d1b949aed',
'Time': '2017-03-16T16:19:02.56Z'
Can somebody help me understand the response? I am facing difficulty to find out the path where the change happened. Also, would this getchanges API capture changes that has happened in subsites within the site?
Yes Lists and Libraries at the end of the day are the same thing. You can get the list title from odata.editLink by stripping off the last segment (Items(1)) in the above case. If you call that path it'll give you the details of the list versus the item/file that was modified. If you want the user's details call /_api/Web/lists/getbytitle('User Information List')/Items(EditorId). If you want the path to the item/file call odata.editlink and the serverrelativeurl parameter returned will have the path to it and title will have the title of the item/file.
Sure, the ChangeType is the main piece of information you need which is an enumerable. You can look up the friendly names for the numbers here: ChangeType Enumeration
So in that case, that looks like an update to the settings of the SPWeb with a guid of '6e21eadd-4155-494d-9a8e-1046865bdd4b'
You may also want to look at using the $expand operator in your REST query to get additional fields back.

Python will not patch json in ConnectWise.

I am a little confused why the following will not work.
I am connecting to our ConnectWise API via requests. I get the response and then I parse through to find the tickets I am looking for. I am then trying to PATCH the ticket to change certain information.
Sample json that is returned via API.
{
"id": 12345,
"summary": "[CompanyName][ComputerName] Disk Space Check - drive G:",
"recordType": "ServiceTicket",
"board": {
"id": 1,
"name": "Board1",
},
"status": {
"id": 5,
"name": "NewTicket",
},
"owner": {
"id": 1,
"identifier": "",
Once I have identified the ticket I need to work with. I try to patch it.
def assign_ticket(self, ticket):
add_resource = [
{'op': 'replace', 'path': '/board/name', 'value': 'Board2'},
{'op': 'replace', 'path': '/status/name', 'value': 'NewTicket2'},
{'op': 'replace', 'path': '/owner/identifier', 'value': 'MyBrainHurts'}
]
r = requests.patch(self.url + self.url_ticket + str(ticket), json=add_resource, headers=self.header)
print(r.status_code)
It returns a 200 status code to indicate everything completely correctly, but only the /owner/identifier field is updated. The other two are not. I have Google'd for several days and tried multiple variations of the code but I do not see why it will not change the board or status. Any ideas?
I've just checked some of my other code and I'm patching successfully using an array, but I'm using the ID of the resource rather than the name. Try that; instead of /status/name use /status/id and a numerical value.
What is the result of r.text? That should either return the configuration in its new, patched, form or it will tell you why the patch didn't work.

How to do a custom insert inside a python-eve app

I have some custom flask methods in an eve app that need to communicate with a telnet device and return a result, but I also want to pre-populate data into some resources after retrieving data from this telnet device, like so:
#app.route("/get_vlan_description", methods=['POST'])
def get_vlan_description():
switch = prepare_switch(request)
result = dispatch_switch_command(switch, 'get_vlan_description')
# TODO: populate vlans resource with result data and return status
My settings.py looks like this:
SERVER_NAME = '127.0.0.1:5000'
DOMAIN = {
'vlans': {
'id': {
'type': 'integer',
'required': True,
'unique': True
},
'subnet': {
'type': 'string',
'required': True
},
'description': {
'type': 'boolean',
'default': False
}
}
}
I'm having trouble finding docs or source code for how to access a mongo resource directly and insert this data.
Have you looked into the on_insert hook? From the documentation:
When documents are about to be stored in the database, both on_insert(resource, documents) and on_insert_<resource>(documents) events are raised. Callback functions could hook into these events to arbitrarily add new fields, or edit existing ones. on_insert is raised on every resource being updated while on_insert_<resource> is raised when the <resource> endpoint has been hit with a POST request. In both circumstances, the event will be raised only if at least one document passed validation and is going to be inserted. documents is a list and only contains documents ready for insertion (payload documents that did not pass validation are not included).
So, if I get what you want to achieve, you could have something like this:
def telnet_service(resource, documents):
"""
fetch data from telnet device;
update 'documents' accordingly
"""
pass
app = Eve()
app.on_insert += telnet_service
if __name__ == "__main__":
app.run()
Note that this way you don't have to mess with the database directly as Eve will take care of that.
If you don't want to store the telnet data but only send it back along with the fetched documents, you can hook to on_fetch instead.
Lastly, if you really want to use the data layer you can use app.data.driveras seen in this example snippet.
use post_internal
Usage example:
from run import app
from eve.methods.post import post_internal
payload = {
"firstname": "Ray",
"lastname": "LaMontagne",
"role": ["contributor"]
}
with app.test_request_context():
x = post_internal('people', payload)
print(x)

Categories

Resources