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.
Related
Hi team i need to fix the 12200 - Schema validation warning twilio.
everything is working but i dont receive the whatsapp respond back .
enter image description here
here is the app.py code:
from helper.openai_api import text_complition
from helper.twilio_api import send_message
from twilio.twiml.messaging_response import MessagingResponse
from flask import Flask, request
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
#app.route('/')
def home():
return 'All is well...'
#app.route('/twilio/receiveMessage', methods=['POST'])
def receiveMessage():
try:
message = request.form['Body']
sender_id = request.form['From']
# Placeholder code
result = {}
result['status'] = 1
result['response'] = "Hi, I'm CODAI, I have received your message."
send_message(sender_id, result['response'])
except:
pass
return 'OK', 200
here is the openai.py code:
import os
import openai
from dotenv import load_dotenv
from twilio.twiml.messaging_response import MessagingResponse
load_dotenv()
openai.api_key = os.getenv('OPENAI_API_KEY')
def text_complition(prompt: str) -> dict:
'''
Call Openai API for text completion
Parameters:
- prompt: user query (str)
Returns:
- dict
'''
try:
response = openai.Completion.create(
model='text-davinci-003',
prompt=f'Human: {prompt}\nAI: ',
temperature=0.9,
max_tokens=150,
top_p=1,
frequency_penalty=0,
presence_penalty=0.6,
stop=['Human:', 'AI:']
)
return {
'status': 1,
'response': response['choices'][0]['text']
}
except:
return {
'status': 0,
'response': ''
}
here is the twilio.py code:
import os
from twilio.twiml.messaging_response import MessagingResponse
from twilio.rest import Client
from dotenv import load_dotenv
load_dotenv()
account_sid = os.getenv('TWILIO_ACCOUNT_SID')
auth_token = os.getenv('TWILIO_AUTH_TOKEN')
client = Client(account_sid, auth_token)
def send_message(to: str, message: str) -> None:
'''
Send message through Twilio's WhatsApp API.
Parameters:
- to(str): recipient's phone number in the format of "whatsapp:+[country code][phone number]"
- message(str): text message to send
Returns:
- None
'''
_ = client.messages.create(
from_=os.getenv('FROM'),
body=message,
to="whatsapp:" + to
)
i need help to fix the error 12200 - Schema validation warning twilio
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?
I'm trying to set up Superset with Auth0. I've found somewhat similar issues here and here.
I've set up the following configuration based on the first link above and trying to follow the Superset and Flask-AppBuilder docs:
from flask_appbuilder.security.manager import (
AUTH_OAUTH,
)
from superset.security import SupersetSecurityManager
import json
import logging
import string
import random
nonce = ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k = 30))
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Admin"
AUTH0_URL = os.getenv('AUTH0_URL')
AUTH0_CLIENT_KEY = os.getenv('AUTH0_CLIENT_KEY')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')
OAUTH_PROVIDERS = [
{ 'name':'auth0',
'token_key':'access_token',
'icon':'fa-at',
'remote_app': {
'api_base_url': AUTH0_URL,
'client_id': AUTH0_CLIENT_KEY,
'client_secret': AUTH0_CLIENT_SECRET,
'server_metadata_url': AUTH0_URL + '/.well-known/openid-configuration',
'client_kwargs': {
'scope': 'openid profile email'
},
'response_type': 'code token',
'nonce': nonce,
}
}
]
class CustomSsoSecurityManager(SupersetSecurityManager):
def oauth_user_info(self, provider, response=None):
logger.debug('oauth2 provider: {0}'.format(provider))
if provider == 'auth0':
res = self.appbuilder.sm.oauth_remotes[provider].get(AUTH0_URL + '/userinfo')
logger.debug('response: {0}'.format(res))
if res.raw.status != 200:
logger.error('Failed to obtain user info: %s', res.json())
return
# user_info = self.appbuilder.sm.oauth_remotes[provider].parse_id_token(res)
# logger.debug('user_info: {0}'.format(user_info))
me = res.json()
return {
'username' : me['email'],
'name' : me['name'],
'email' : me['email'],
}
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
The full error log message is:
2022-03-18 18:53:56,854:ERROR:flask_appbuilder.security.views:Error authorizing OAuth access token: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
NOTES:
I can see an access_token parameter in the redirect url, so it seems to be working with Auth0 correctly.
I don't see any of the debug lines in the CustomSsoSecurityManager being written, so my guess is that I have not correctly set that up (or my logging is not correctly configured).
I've tried using both Regular Web Application and Single Page Application application types in Auth0, and both fail in the same way.
I would appreciate any help in understanding what I might be missing or what else I need to do to configure Auth0 to work with Superset.
I was able to make it work using the JSON Web Key Set endpoint provided by Auth0, look at this example and adapt it accordingly:
from jose import jwt
from requests import request
from superset.security import SupersetSecurityManager
class CustomSecurityManager(SupersetSecurityManager):
def request(self, url, method="GET", *args, **kwargs):
kwargs.setdefault("headers", {})
response = request(method, url, *args, **kwargs)
response.raise_for_status()
return response
def get_jwks(self, url, *args, **kwargs):
return self.request(url, *args, **kwargs).json()
def get_oauth_user_info(self, provider, response=None):
if provider == "auth0":
id_token = response["id_token"]
metadata = self.appbuilder.sm.oauth_remotes[provider].server_metadata
jwks = self.get_jwks(metadata["jwks_uri"])
audience = self.appbuilder.sm.oauth_remotes[provider].client_id
payload = jwt.decode(
id_token,
jwks,
algorithms=["RS256"],
audience=audience,
issuer=metadata["issuer"],
)
first_name, last_name = payload["name"].split(" ", 1)
return {
"email": payload["email"],
"username": payload["email"],
"first_name": first_name,
"last_name": last_name,
}
return super().get_oauth_user_info(provider, response)
So every time I run my code it gives a link on my terminal that I have to manually press on and choose my Gmail account on browser to login and receive an authorization code. That again I have to paste onto my terminal.
Is there a way to skip this process?
The code I'm using:
# -*- coding: utf-8 -*-
# Sample Python code for youtube.videos.update
# See instructions for running these code samples locally:
# https://developers.google.com/explorer-help/guides/code_samples#python
import os
import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors
scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]
def main():
# Disable OAuthlib's HTTPS verification when running locally.
# *DO NOT* leave this option enabled in production.
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
api_service_name = "youtube"
api_version = "v3"
client_secrets_file = "client_secret_key.json"
# Get credentials and create an API client
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
credentials = flow.run_console()
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
request = youtube.videos().update(
part="id,snippet",
body={
"id": "videoid",
"snippet": {
"title": "XOXOXO",
"description": "Through IDE",
"categoryId": "27"
}
}
)
response = request.execute()
print(response)
if __name__ == "__main__":
main()
Indeed there's the possibility to save your credentials object the first time running successfully an OAuth authorization/authentication flow; then to load the credentials object from that file each time running the program for the n-th time, where n >= 2.
Here is how I recommend to structure your code:
import os, pickle
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
def pickle_file_name(
api_name = 'youtube',
api_version = 'v3'):
return f'token_{api_name}_{api_version}.pickle'
def load_credentials(
api_name = 'youtube',
api_version = 'v3'):
pickle_file = pickle_file_name(
api_name, api_version)
if not os.path.exists(pickle_file):
return None
with open(pickle_file, 'rb') as token:
return pickle.load(token)
def save_credentials(
cred, api_name = 'youtube',
api_version = 'v3'):
pickle_file = pickle_file_name(
api_name, api_version)
with open(pickle_file, 'wb') as token:
pickle.dump(cred, token)
def create_service(
client_secret_file, scopes,
api_name = 'youtube',
api_version = 'v3'):
print(client_secret_file, scopes,
api_name, api_version,
sep = ', ')
cred = load_credentials(api_name, api_version)
if not cred or not cred.valid:
if cred and cred.expired and cred.refresh_token:
cred.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
client_secret_file, scopes)
cred = flow.run_console()
save_credentials(cred, api_name, api_version)
try:
service = build(api_name, api_version, credentials = cred)
print(api_name, 'service created successfully')
return service
except Exception as e:
print(api_name, 'service creation failed:', e)
return None
def main():
youtube = create_service("client_secret_key.json",
["https://www.googleapis.com/auth/youtube.force-ssl"])
if not youtube: return
request = youtube.videos().update(
part="id,snippet",
body={
"id": "videoid",
"snippet": {
"title": "XOXOXO",
"description": "Through IDE",
"categoryId": "27"
}
}
)
response = request.execute()
print(response)
if __name__ == '__main__':
main()
You have to be aware of the following peculiarity of the code above: if you run your script the second time from within a different directory than the one from within you've ran it the first time, the script will reinitiate an OAuth flow when that (current) directory does not contain a credentials pickle file.
Now, if you have installed (or otherwise are willing to install) the package Google Authentication Library for Python, google-auth, version >= 1.21.3 (google-auth v1.3.0 introduced Credentials.from_authorized_user_file, v1.8.0 introduced Credentials.to_json and v1.21.3 fixed this latter function w.r.t. its class' expiry member), then you may have your credentials object saved to and load from a JSON text file.
Here is the code that'll do that:
import os, json, io
...
def json_file_name(
api_name = 'youtube',
api_version = 'v3'):
return f'token_{api_name}_{api_version}.json'
def load_credentials(
api_name = 'youtube',
api_version = 'v3'):
cred_file = json_file_name(
api_name, api_version)
if not os.path.exists(cred_file):
return None
from google.oauth2.credentials import Credentials
return Credentials.from_authorized_user_file(cred_file)
def save_credentials(
cred, api_name = 'youtube',
api_version = 'v3'):
cred_file = json_file_name(
api_name, api_version)
with io.open(cred_file, 'w', encoding = 'UTF-8') as json_file:
json_file.write(cred.to_json())
...
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