Slack modal view immediately closes when using views.push - python

I'm creating a Slack app using Python and Flask. The app uses a Slack modal with two views: The first is opened when a slash command is given and the second should be opened when the user presses the submit button on the first view. When I run this, the first view opens correctly. However, when I try to push the second view it opens and then closes immediately, reverting back to the first view without any interaction from the user.
I have tried using the notify_on_close flag to see if the second view is being closed for some reason, however I am not getting any 'form closed' messages after the second view closes.
Here is an example of where this problem occurs:
#app.route('/slash_command', methods=['POST'])
def open_modal():
trigger_id = request.form['trigger_id']
sc.views_open(trigger_id=trigger_id, view=views.first_view)
return '', 200
#app.route('/actions', methods=['POST'])
def action_endpoint():
payload = json.loads(request.form['payload'])
callback_id = payload['view']['callback_id']
trigger_id = payload['trigger_id']
# Push the second view if the first view is submitted
if callback_id == 'first_view':
sc.views_push(trigger_id=trigger_id, view=views.second_view)
return '', 200
My views are very simple:
first_view = {
"type": "modal",
'callback_id': 'first_view',
"title": {
"type": "plain_text",
"text": "First View"
},
"submit": {
"type": "plain_text",
"text": "Submit"
},
"close": {
"type": "plain_text",
"text": "Cancel"
},
'blocks': []
}
second_view = {
'type': 'modal',
'callback_id': 'second_view',
'title': {
'type': 'plain_text',
'text': 'Second View',
},
'submit': {
'type': 'plain_text',
'text': 'Submit'
},
'close': {
'type': 'plain_text',
'text': 'Cancel'
},
'blocks': []
}

Slack support resolved this by explaining that the above code pushes a new view and then returns a 200 response, which is interpreted by Slack as a request to close the current view. I was able to make the code work correctly by updating it as follows:
# Push the second view if the first view is submitted
if callback_id == 'first_view':
return {
'response_action': 'push',
'view': views.second_view
}
return '', 200

Related

Django/Graphene seems to clean database between individual tests in a test run

I'm testing Django/Graphene to see if it can fulfill what I need, but I'm getting trouble in unit testing.
I'm using the in-memory SQLite db, with the following code (tests.py):
import json
from graphene_django.utils.testing import GraphQLTestCase
from graphene.test import Client
from users.schema import UserType
class APITestCase(GraphQLTestCase):
def test01_query_users(self):
print("Running test01_query_users")
response = self.query(
'''
query {
users {
id
username
email
}
}
'''
)
print (response)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
print (content)
assert content == {
"data": {
"users": []
}
}
def test02_mutation_addUser(self):
print("Running test02_mutation_addUser")
response = self.query(
'''
mutation {
createUser (username: "testuser", email: "testemail#testserver.com", password: "123456") {
user {
id
username
email
}
}
}
'''
)
print (response)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
print (content)
assert content == {
"data": {
"createUser": {
"user": {
"id": "1",
"username": "testuser",
"email": "testemail#testserver.com"
}
}
}
}
def test03_mutation_addUser(self):
print("Running test03_mutation_addUser")
response = self.query(
'''
mutation {
createUser (username: "testuser2", email: "testemail2#testserver.com", password: "123456") {
user {
id
username
email
}
}
}
'''
)
print (response)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
print (content)
assert content == {
"data": {
"createUser": {
"user": {
"id": "2",
"username": "testuser2",
"email": "testemail2#testserver.com"
}
}
}
}
def test04_query_users(self):
print("Running test04_query_users")
response = self.query(
'''
query {
users {
id
username
email
}
}
'''
)
print (response)
content = json.loads(response.content)
self.assertResponseNoErrors(response)
print (content)
assert content == {
"data": {
"users": []
}
}
The test output is as follows:
Using existing test database for alias 'default'...
System check identified no issues (0 silenced).
Running test01_query_users
<HttpResponse status_code=200, "application/json">
{'data': {'users': []}}
.Running test02_mutation_addUser
<HttpResponse status_code=200, "application/json">
{'data': {'createUser': {'user': {'id': '1', 'username': 'testuser', 'email': 'testemail#testserver.com'}}}}
.Running test03_mutation_addUser
<HttpResponse status_code=200, "application/json">
{'data': {'createUser': {'user': {'id': '1', 'username': 'testuser2', 'email': 'testemail2#testserver.com'}}}}
FRunning test04_query_users
<HttpResponse status_code=200, "application/json">
{'data': {'users': []}}
.
======================================================================
FAIL: test03_mutation_addUser (polls.tests.tests.APITestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\myuser\Projects\Python\virtual-environments\myproject\tests\tests.py", line 89, in test03_mutation_addUser
assert content == {
AssertionError
----------------------------------------------------------------------
Ran 4 tests in 0.980s
FAILED (failures=1)
It runs first test just ok, then the 2nd one ok, adding a user. When it runs the 3rd it returns a different user with the same ID of the previous one, as if the previous mutation's results was wiped out from the DB, failing because the expected ID (2) is not met. When the 4th test is executed it shows the DB has 0 users. The expected result should be a DB with two different users.
Why it seems to wipe the DB after each test? What am I doing wrong? When I pass --keepdb it doesn't store the DB anywhere.
The tests must be isolated from each other, and they are by default.
Django wraps every test in a transaction that is rolled back after the test executes, so the data is not visible outside that test method. You should neither rely on any other test side-effects, nor on the order of their execution (i.e. tests can be run in parallel).
So, you have to set up the test data for test04_query_users specifically inside this method. Create some users via i.e. User.objects.create() or some library like Factory Boy and then query and assert for them.

How to create a product successfully using woo commerce api with python

I am trying to create / update products from my django app to my website.
The problem I am facing with is that i can not create the product from my django to the website using the woo commerce api.
The update procedure works.
Here is my code:
def create_woocommerce_product_individually(wcapi,name,fetched_sku,fetched_url,short_description,description,woo_commerce_category_id):
data = {
"name": name,
"sku": fetched_sku,
"images": [
{
"src": fetched_url
},
],
"short_description": short_description,
"description": description,
"categories": [
{
"id": woo_commerce_category_id
}
],
}
#post data to the woocommerce API
wcapi.post("products",data).json()
print(" 3A STEP - WOO PRODUCT CREATED IN THE SITE")
def update_woocommerce_product_individually(wcapi,name,fetched_sku,fetched_url,short_description,description,woo_commerce_category_id,post_id):
data = {
"name": name,
"sku": fetched_sku,
"images": [
{
"src": fetched_url
},
],
"short_description": short_description,
"description": description,
"categories": [
{
"id": woo_commerce_category_id
}
],
}
#put data to the woocommerce API
wcapi.put("products/"+str(post_id),data).json()
print(" 3B STEP - WOO PRODUCT UPDATED IN THE SITE")
Here is the part of code, calling the above functions based on the response:
r=wcapi.get("products/?sku="+fetched_sku).json()
if len(r) > 0:
#if it exists in the website , take the post id
post_id=r[0]['id']
if len(r) == 0:
#call the create
create_woocommerce_product_individually(wcapi,name,fetched_sku,fetched_url,short_description,description,woo_commerce_category_id)
product.is_stored_to_website = True
product.save()
print("Stored : {} \n".format(product.is_stored_to_website))
else:
#call the update
update_woocommerce_product_individually(wcapi,name,fetched_sku,fetched_url,short_description,description,woo_commerce_category_id,post_id)
product.is_stored_to_website = True
product.save()
print("Stored : {} \n".format(product.is_stored_to_website))
I read in some forums that the wordpress theme may be the problem for create. I changed it and the problem not solved.
Am I missing something or writing wrong something related to the api call for create?
Print the API response to see what is going on.
Chage:
wcapi.post("products",data).json()
print(" 3A STEP - WOO PRODUCT CREATED IN THE SITE")
To:
result = wcapi.post("products",data).json()
print(" 3A STEP - WOO PRODUCT CREATED IN THE SITE - {}".format(result))
This is how I do it:
data = {'categories': [{'id': 56}],
'dimensions': {'height': '', 'length': '1990.0', 'width': '1180.0'},
'images': [],
'name': 'Product Name',
'regular_price': '4769',
'short_description': '<h3>Blbalablabal</h3>\n'
'<ul>\n'
'\t<li><strong>caracteristic1: </strong>12.5 mm</li>\n'
'\t<li><strong>caracteristic3: </strong>1.99 x 1.18 m</li>\n'
'\t<li><strong>caracteristic3: </strong>Circular '
'total</li>\n'
'</ul>\n',
'sku': '56565',
'slug': 'product-name',
'status': 'publish',
'type': 'simple',
'weight': ''}
Then add the product:
def add_product(self, data):
return self.API.post("products", data).json()
Hope this helps!

How to run dialog in slack app with flask?

I am in the middle of creating todo app integreted with Slack. I need to use dialog.open property of slack.
I managed to go through slack api tutorial however can not finally understand how dialogs work in integration with external systems. I created code which runs after slash command in slack. It should open dialog and show it to user, however it doesn't. I printed some parts of code to see what happens inside - looks like whole code works and server returns 200.
#app.route('/helpdesk', methods=['POST'])
def helpdesk():
print(request.form)
api_url = 'https://slack.com/api/dialog.open'
user_id = request.form['user_id']
trigger_id = request.form['trigger_id']
dialog = {
"token": "J1llSAeQAxNyw8yc37xuEsad",
"trigger_id": trigger_id,
"dialog": {
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": True,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
}
print(dialog)
requests.post(api_url, data=dialog)
return make_response()
I expect to see dialog window after writing slash command in slack.
What I see in prints:
ImmutableMultiDict([('token', 'J1llSAeQAxNyw8yc37xuEsad'), ('team_id', 'TKWQ5QP7Y'), ('team_domain', 'team-learningslack'), ('channel_id', 'CKH7RSZPC'), ('channel_name', 'slackflask'), ('user_id', 'UKN9KU7JM'), ('user_name', 'konrad.marzec1991'), ('command', '/musi'), ('text', ''), ('response_url', 'https://hooks.slack.com/commands/TKWQ5QP7Y/664885241506/ABjpMYmTWrnXpSBoGMpaJtOV'), ('trigger_id', '669947662833.676821839270.6c4bddd1418d3d4f2c8626f7c9accdf7')])
{'token': 'J1llSAeQAxNyw8yc37xuEsad', 'trigger_id': '669947662833.676821839270.6c4bddd1418d3d4f2c8626f7c9accdf7', 'dialog': {'callback_id': 'ryde-46e2b0', 'title': 'Request a Ride', 'submit_label': 'Request', 'notify_on_cancel': True, 'state': 'Limo', 'elements': [{'type': 'text', 'label': 'Pickup Location', 'name': 'loc_origin'}, {'type': 'text', 'label': 'Dropoff Location', 'name': 'loc_destination'}]}}
127.0.0.1 - - [26/Jun/2019 00:15:35] "POST /helpdesk HTTP/1.1" 200 -
You had 2 issues in your code:
you need to use an access token, not a verification token in the call
to dialog.open
you need to send the dialog definition as JSON, not as as form array
I made these additional changes
- Added code for using a slack token defined as environment variable
- Use the get() method to access form parameters in from the request
- Added code to show the API response from dialog.open
Here is a corrected version of your code:
import os
import requests
from flask import Flask, json, request
app = Flask(__name__) #create the Flask app
#app.route('/helpdesk', methods=['POST'])
def helpdesk():
api_url = 'https://slack.com/api/dialog.open'
trigger_id = request.form.get('trigger_id')
dialog = {
"callback_id": "ryde-46e2b0",
"title": "Request a Ride",
"submit_label": "Request",
"notify_on_cancel": True,
"state": "Limo",
"elements": [
{
"type": "text",
"label": "Pickup Location",
"name": "loc_origin"
},
{
"type": "text",
"label": "Dropoff Location",
"name": "loc_destination"
}
]
}
api_data = {
"token": os.environ['SLACK_TOKEN'],
"trigger_id": trigger_id,
"dialog": json.dumps(dialog)
}
res = requests.post(api_url, data=api_data)
print(res.content)
return make_response()
if __name__ == '__main__':
app.run(debug=True, port=8000) #run app in debug mode on port 8000

paypalrestsdk with Django integration issue

I am trying to setup Paypal express checkout with REST API but when I click checkout with Paypal I get modal window and it just spins forever.
Payment create view:
def payment_create(request):
logging.basicConfig(level=logging.INFO)
paypalrestsdk.configure({
'mode': settings.PAYPAL_MODE,
'client_id': settings.PAYPAL_CLIENT_ID,
'client_secret': settings.PAYPAL_CLIENT_SECRET
})
# Create payment object
payment = paypalrestsdk.Payment({
"intent": "sale",
# Set payment method
"payer": {
"payment_method": "paypal"},
# Set redirect urls
"redirect_urls": {
"return_url": "http://127.0.0.1:8000/checkout/payment_done/",
"cancel_url": "http://127.0.0.1:8000/checkout/payment_error/"},
# Set transaction object
"transactions": [{
"amount": {
"total": "10.00",
"currency": "USD"},
"description": "payment description"}]})
# Create Payment and return status
if payment.create():
print("Payment[%s] created successfully" % (payment.id))
request.session["paymentID"] = payment.id
# Redirect the user to given approval url
for link in payment.links:
if link.method == "REDIRECT":
print("Redirect for approval: %s" % (link.href))
return HttpResponseRedirect(link.href)
else:
print("Error while creating payment:")
print(payment.error)
Cart.html template:
<div id="paypal-button"></div>
<script src="https://www.paypalobjects.com/api/checkout.js" data-version-4></script>
<script>
paypal.Button.render({
env: 'sandbox', // Optional: specify 'sandbox' environment
payment: function(resolve, reject) {
var CREATE_PAYMENT_URL = 'http://127.0.0.1:8000/checkout/payment_create/';
paypal.request.post(CREATE_PAYMENT_URL)
.then(function(data) { resolve(data.paymentID); })
.catch(function(err) { reject(err); });
},
onAuthorize: function(data) {
// Note: you can display a confirmation page before executing
var EXECUTE_PAYMENT_URL = 'http://127.0.0.1:8000/checkout/payment_execute/';
paypal.request.post(EXECUTE_PAYMENT_URL,
{ paymentID: data.paymentID, payerID: data.payerID })
.then(function(data) { window.location.replace("http://127.0.0.1:8000/checkout/payment_done/") })
.catch(function(err) { window.location.replace("http://127.0.0.1:8000/checkout/payment_error/") });
}
}, '#paypal-button');
</script>
From logs looks like I am successfully creating payment object, but failing to redirect, in dev tools i am seeing this:
VM6073:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse ()
at XMLHttpRequest. (https://www.paypalobjects.com/api/checkout.js:10511:38)
After researching online seems like json is expected but i am returning html? Can anyone point me in the right direction.
I am new to programming so any help is appreciated!

How to get previous object value after changing its name using django reversion?

In How to add django-reversion to an app developed using django and django-rest framework I have added the below function to get history of objects
from django.http import HttpResponse
from reversion.models import Version
import json
def history_list(request):
history_list = Version.objects.all().order_by('-revision__date_created')
data = []
for i in history_list:
data.append({
'date_time': str(i.revision.date_created),
'user': str(i.revision.user),
'object': i.object_repr,
'type': i.content_type.name,
'comment': i.revision.comment
})
data_ser = json.dumps(data)
return HttpResponse(data_ser, content_type="application/json")
In the urls.py of How to add django-reversion to an app developed using django and django-rest framework I have added a route to history.
When I visit 127.0.0.1:8000/history I get the json data as
[{"object": "someobject", "user": "someuseruser", "type": "sometype", "comment": "Changed name.", "date_time": "2015-03-02 18:04:58.368650+00:00"}]
execution flow: When I visit 127.0.0.1:8000/admin and change the value of above object to "otherobject". when I refresh 127.0.0.1:8000/history. I get one more json field
[{"object": "otherobject", "user": "someuseruser", "type": "sometype", "comment": "Changed name.", "date_time": "2015-03-02 18:04:58.368650+00:00"}]
below is the area I got stuck to add one more additional field to history function:
I would like to include one more field to above iteration in history function. like previous_object: " " to get the object name before its changed even after changing name.
for instance:-
from 127.0.0.1:8000/admin
I changed object name from "apple" to "orange".
When I visit the history route 127.0.0.1:8000/history
[{"object": "apple", "object_before_changed": ""null": "someuseruser", "type": "sometype", "comment": "Changed name.", "date_time": "2015-03-02 18:00:58.368650+00:00"}]
I should be able to see as below
[{"object": "orange", "object before_changed": ""apple": "someuseruser", "type": "sometype", "comment": "Changed name.", "date_time": "2015-03-02 18:04:58.368650+00:00"}]
You just need to setup a variable to hold to previous item and insert it into the dictionary as required. note that this uses getattr as a way to get the object_repr of previous_object and safely provide a default if there is none (as would be the case for the first iteration).
data = []
previous_object = None
for i in history_list:
data.append({
'date_time': str(i.revision.date_created),
'user': str(i.revision.user),
'object': i.object_repr,
'previous_object': getattr(previous_object,'object_repr',None),
'type': i.content_type.name,
'comment': i.revision.comment
})
previous_object = i

Categories

Resources