What's the structure of Telegram's updates to webhook Flask app? - flask

I'm trying to program a Telegram bot using webhook in a Flask app with telepot, in PythonAnywhere. And so, I want to know what's the structure of the updates comming from Telegram, so as to know what's there and how is it called, and use it in the bot, essentially.
I've tried to log the message it receives to the console (though I'm not sure where the console should be on PythonAnywhere), and also to write in a file in the same server, through python, but that's not working either.
#This that seemed easy didn't work either in the Flask web app
with open('log.txt', 'a') as f:
f.write('Is this working?')
It feels like I'm missing some easy information everyone takes for granted, but I can't figure out what that is.

There was indeed something I didn't notice. Posting in case it helps anyone.
On the web app section of PythonAnywhere there are three Log Files links where you can see the kinds of things that would apear on the console in a regular Python app.
Those links look like this:
username.eu.pythonanywhere.com.access.log
username.eu.pythonanywhere.com.error.log
username.eu.pythonanywhere.com.server.log #no .eu on the american PythonAnywhere
And server.log is where console print statements end up.
Also, regular messages from Telegram users look like this when they arrive to Flask:
{
'update_id': 123456789,
'message': {
'message_id': 42,
'from': {
'id': 42424242,
'is_bot': False,
'first_name': 'Joaquim',
'last_name': 'Pernil Rinoceronts',
'username': 'Juqim',
'language_code': 'ca'
},
'chat': {
'id': 42424242,
'first_name': 'Joaquim',
'last_name': 'Pernil Rinoceronts',
'username': 'Juqim',
'type': 'private'
},
'date': 1562247903,
'text': 'Patata'
}
}
Stickers have their info where 'text' would be:
'sticker': {
'width': 512,
'height': 512,
'emoji': '😒',
'set_name': 'Ruscamems',
'thumb': {
'file_id': 'AAQEABNgnrsaAAQkkp4QRiVF1rokAAIC',
'file_size': 4840,
'width': 128,
'height': 128
},
'file_id': 'CAADBAADBQADkvulAumgmwOAjdfYAg',
'file_size': 36612
}
Images have 'photo' instead, and they come in a collection of different sizes:
'photo':[
{
'file_id': 'AgADBAADVrAxG2wj8FCs-f6v7AGFUQvo-RkABFGq4cIH4_MaHXIFAAEC',
'file_size': 2101,
'width': 66,
'height': 90
},
{
#same but bigger (different id too)
},
... #I got 4 sizes.
]
I guess I'll post the callback too and we'll have most of the interesting stuff:
{
'update_id': 123456793,
'callback_query': {
'id': '424242424242424242',
'from': { #Who pressed the Button
'id': 42424242,
'is_bot': False,
'first_name': 'Joaquim',
'last_name': 'Pernil Rinoceronts',
'username': 'Juqim',
'language_code': 'ca'
},
'message': { #What message was the button in
'message_id': 123,
'from': {
'id': 434343434,
'is_bot': True,
'first_name': 'The Bot Name',
'username': 'name_bot'
},
'chat': {
'id': 42424242,
'first_name': 'Joaquim',
'last_name': 'Pernil Rinoceronts',
'username': 'Juqim',
'type': 'private'
},
'date': 1562252792,
'text': 'A viam si funciona això',
'reply_markup': { #Keyboard pressed
'inline_keyboard': [[{'text': 'Cliccami', 'callback_data': 'clicat'}]]
}
},
'chat_instance': '1234123412341234242',
'data': 'clicat' #Callback data (button pressed)
}
}

Related

Testing a PUT request in Django Rest Framework

When I run this test
def test_update_car(self):
new_car = Car.objects.create(make='Chevy', model='Equinox', year=2012, seats=4, color='green', VIN='12345671234567abc', current_mileage=19000, service_interval='3 months', next_service='april')
url = reverse('car-detail', kwargs={'pk': new_car.pk})
data = {
'make': 'test',
'model': 'test',
'year': 2014,
'seats': 5,
'color': 'blue',
'VIN': '12345671234567abc',
'current_mileage': 20000,
'service_interval': '6 months',
'next_service': 'July',
}
response = self.client.put(url, data=data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(new_car.make, 'test')
I get an assertion error
AssertionError: 'Chevy' != 'test'
How should I structure this differently so that the PUT request actually changes the make and model of the new_car?
If your view indeed responds to a PUT request, the problem is located at the test itself. You need to refresh the data from the database with .refresh_from_db(…) [Django-doc]:
def test_update_car(self):
new_car = Car.objects.create(make='Chevy', model='Equinox', year=2012, seats=4, color='green', VIN='12345671234567abc', current_mileage=19000, service_interval='3 months', next_service='april')
url = reverse('car-detail', kwargs={'pk': new_car.pk})
data = {
'make': 'test',
'model': 'test',
'year': 2014,
'seats': 5,
'color': 'blue',
'VIN': '12345671234567abc',
'current_mileage': 20000,
'service_interval': '6 months',
'next_service': 'July',
}
response = self.client.put(url, data=data)
new_car.refresh_from_db()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(new_car.make, 'test')

Django extract field form html

I have a html page that returns data in a form. The forms is a multiple choice checkbox field with "name=states1". When I run print(vars(self)) in my forms.py I see that the data is there ['MD', 'WV', 'WY'] (see below) however, when I try to extract it with print(self.data['states1']) I just get 'WY' and print(len(self.data['states1'])) returns 2.
{'instance': <AA: AAobject>, '_validate_unique': False, 'is_bound': True, 'data': <QueryDict: {'csrfmiddlewaretoken': ['AAAAA']: ['1'], 'states1': ['MD', 'WV', 'WY'], 'states': [''], 'price': ['2.00'], 'user': ['1', '1']}>, ...
However, when I run
import json
print(json.dumps(self.data, indent=2))
I get the following output
{
"csrfmiddlewaretoken": "AAAAA",
"roles": "1",
"states1": "WY",
"states": "",
"price": "2.00",
"user": "1"
}
The data is just gone. Why is my data being restricted to the last field, when I can clearly see it when looking at vars?
forms.py
class UserProfileChangeForm(forms.ModelForm):
states = forms.CharField(widget=USStateSelect(), initial='TX', required=False)
class Meta:
model = SkilledLaborer
fields = ['user','roles','travel_flag','price','states']
def clean_states(self):
print('states')
states = self.cleaned_data['states']
print(type(vars(self)))
print(vars(self).keys())
print(vars(self))
print(self.data.keys())
print(self.data['states1'])
print(len(self.data['states1']))
import json
print(json.dumps(self.data, indent=2))
try:
self.data['states1']
except:
pass
return states

django test - how to get response data for future use

I'm running a login test like so:
def test_login_user(self):
client = APIClient()
url = reverse('rest_login')
data = {
'username': 'test',
'password': 'Welcome2'
}
response = self.client.post(url, data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
client.logout()
If I login to the app normally I see a json return like this:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6ImV2YW4iLCJleHAiOjE1MTQ2NzYzNTYsImVtYWlsIjoiZXZhbkAyOGJlYXR0eS5jb20iLCJvcmlnX2lhdCI6MTUxNDY3Mjc1Nn0.8CfhfgtMLkNjEaWBfNXbUWXQMZG4_LIru_y4pdLlmeI",
"user": {
"pk": 2,
"username": "test",
"email": "test#test.com",
"first_name": "",
"last_name": ""
}
}
I want to be able to grab that token value for future use however the response does not seem to have a data value to grab.
What I'm looking for is response.content per the official documentation
https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testing-responses
You can use response.json()['token'] to get data from the token field.
Usage as below:
token = response.json()['token'];
show error response:
response.context["form"].errors

What are the different dicts in Django Debug Toolbar's 'Toggle context' areas?

Using Django Debug Toolbar I can go to the 'Templates' panel and click the 'Toggle context' links to see the context at any point.
Each of these shows more than one dict, eg:
{'False': False, 'None': None, 'True': True}
{'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10,
'ERROR': 40,
'INFO': 20,
'SUCCESS': 25,
'WARNING': 30},
'csrf_token': <SimpleLazyObject: 'zJvE5t6k9KdxMfUmU4SOvRTOC2rh7Pvw'>,
'debug': True,
'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x10877b860>,
'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x10877de10>,
'request': '<<request>>',
'sql_queries': <function debug.<locals>.<lambda> at 0x108d3de18>,
'user': <SimpleLazyObject: <User: phil>>}
{'is_paginated': True,
'object_list': '<<queryset of twitter.Tweet>>',
'page_obj': <Page 1 of 330>,
'paginator': <ditto.ditto.paginator.DiggPaginator object at 0x10877bac8>,
'view': <ditto.twitter.views.TweetList object at 0x108782dd8>}
What are the three different dicts shown here? Why not one?
Django templates have something called scopes. Each scope is an layer of variables, available only in current scope and all child scopes.
Each of 'layers' that are responsible for rendering template will add it's own scope. By default there are 3 scopes: root scope, that will have some definitions of constant variables:
{'False': False, 'None': None, 'True': True}
context_processors scope, that will contain all variables injected into your templates globally from context processors:
{'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10,
'ERROR': 40,
'INFO': 20,
'SUCCESS': 25,
'WARNING': 30},
'csrf_token': <SimpleLazyObject: 'zJvE5t6k9KdxMfUmU4SOvRTOC2rh7Pvw'>,
'debug': True,
'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x10877b860>,
'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x10877de10>,
'request': '<<request>>',
'sql_queries': <function debug.<locals>.<lambda> at 0x108d3de18>,
'user': <SimpleLazyObject: <User: phil>>}
And Response scope, that will have all variables passed into Response object:
{'is_paginated': True,
'object_list': '<<queryset of twitter.Tweet>>',
'page_obj': <Page 1 of 330>,
'paginator': <ditto.ditto.paginator.DiggPaginator object at 0x10877bac8>,
'view': <ditto.twitter.views.TweetList object at 0x108782dd8>}
There are listed in order from oldest one (root) to youngest one, that means: all variables mentioned in dicts mentioned later will cover variables mentioned above.
Additional scopes can be created by some template tags, for example for loop, where, include... That scopes won't be visible in django debug toolbar.

django test for upload image

i want to test user registration but i can't test image here is my test:
test.py
response = self.client.post('/api/v1/signup/',
content_type='application/json',
data=json.dumps({"username": "casino", "email": "casinoluxwin#gmail.com",
"password1": "android12", "password2": "android12", "photo": {
'real_filename': "u'banner3.jpg'",
'path': "u'C:/Users/Dima/Desktop'"}
}))
self.assertEqual(response.status_code, 200)
i get code 400(bad request), but without photo my test pass
service/users.py
#validate_input({
'username': {'min_length': 3, 'max_length': 50},
'email': {'validation_type': "email", 'max_length': 50},
'password1': {'min_length': 8, 'max_length': 50},
'password2': {'min_length': 8, 'equal_to': 'password1',
'messages': {'equal_to': _(u"Пароли не совпадают")}},
'photo': {'required': True}
})
#transaction.atomic
def signup(self, data):
user_data = {
'username': data['username'],
'email': data['email'],
'password': data['password1'],
'coins_amount': 0
}
user = self._create_user(user_data)
if data.get("photo"):
self._attach_photo(user, data["photo"])
obj, created = VerificationCode.objects.get_or_create(user=user, code_type="registration")
obj.create_expiration_date()
obj.create_code()
obj.save()
return user.id
So i want to test user photo anything else works fine. Thanks for any help
Problem probably resides in either Users._attach_photo() or your user model. Not enough information here to decipher it entirely. There are a couple of things to try.
I'd write a normal unittest that does not use the client. It'll give you a more helpful traceback than just the HTTP status code from the running server. Something like:
def test_user_add_method(self):
x = Users.signup(json.dumps({"username": "casino", "email": "casinoluxwin#gmail.com",
"password1": "android12", "password2": "android12", "photo": {
'real_filename': "u'banner3.jpg'",
'path': "u'C:/Users/Dima/Desktop'"})
Users.get(pk=x) #will fail if user was not created.
Second, try commenting out your validator. 400 bad request could easily be kicked off by that. It is possible that your validator isn't playing nice with the image and you'll have to mess around with that.