Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Work In Progress] Base Code for Server, Authorization, and Messages #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions app/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# app/auth.py
"""Handles all auth related APIs."""

import datetime
import json
import requests

class AuthManager:
"""Authorization Manager."""

LOGIN_URL = "https://api.staging.tides.coloredcow.com/api/v1/session"
RENEW_URL = "https://api.staging.tides.coloredcow.com/api/v1/session/renew"

def __init__(self):
self.access_token = None
self.renewal_token = None
self.expiry_time = None

def login(self):
"""Create a new session for an existing user."""

payload = json.dumps({
"user": {
"phone": "917834811114",
"password": "secret1234"
}
})

headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}

response = requests.request("POST", self.LOGIN_URL, headers=headers, data=payload)

print(response.text)

if response.status_code == 200:
data = response.json()
self.access_token = data.get('access_token')
self.renewal_token = data.get('renewal_token')
self.expiry_time = (datetime.datetime.now() +
datetime.timedelta(seconds=data.get('token_expiry_time')))
return True
return False

def renew_token(self):
"""Renew an existing session."""

payload = json.dumps({
"data": {
"data": {
"access_token": self.access_token,
"renewal_token": self.renewal_token,
}
}
})

# TODO: Confirm if this = 'Authorization key which includes the renew token.'
# Seems like this is expected according to api.docs/includes/_auth.md line 120.

headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': self.access_token,
}

response = requests.request("POST", self.RENEW_URL, headers=headers, data=payload)

print(response.text)

# TODO: Found format of respnse returned in api.docs/includes/_auth.md,
# glific api docs (https://api.glific.com/#23b77640-b818-459b-88e0-3437665bf7ad)
# say no response returned

if response.status_code == 200:
data = response.json()
self.access_token = data.get('access_token')
self.renewal_token = data.get('renewal_token')
self.expiry_time = datetime.datetime.now() + datetime.timedelta(
seconds=data.get('token_expiry_time'))
return True
return False

def is_token_expired(self):
"""Check if the token has expired"""
return datetime.datetime.now() >= self.expiry_time
66 changes: 66 additions & 0 deletions app/messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# app/glific_api.py
"""Handles message related API requests (Create + Send for now)."""

import json
import requests

class MsgManager:
"""Message Manager."""

SEND_MSG_URL = "https://api.staging.tides.coloredcow.com/api"

def __init__(self, auth_manager):
self.auth_manager = auth_manager

def send_message(self, contact_id, message):
"""Create + Send a Message."""
payload= json.dumps({
"query": """
mutation createAndSendMessage($input: MessageInput!) {
createAndSendMessage(input: $input) {
message {
id
body
receiver {
id
name
}
}
errors {
key
message
}
}
}
""",
"variables": {
"input": {
"body": message.body,
"flow": "OUTBOUND",
# "isHSM": False,
# "mediaId": 2,
# "params": [],
# "templateId": 4,
# "type": "TEXT",
# TODO: What should values here be?
"senderId": contact_id,
"receiverId": contact_id,
}
}
})


# TODO: Confirm this access token == auth token used in api description.
headers = {
'authorization': self.auth_manager.access_token,
'Content-Type': 'application/json'
}

response = requests.request("POST", self.SEND_MSG_URL, headers=headers, data=payload)

print(response.text)

# TODO: Confirm no data members need to be modified when message sent
if response.status_code == 200:
return True
return False
51 changes: 51 additions & 0 deletions app/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# app/server.py
""" Long-running server, implements auth + send message functionalities."""

from flask import Flask, request, jsonify
from apscheduler.schedulers.background import BackgroundScheduler
from app.auth import AuthManager
from app.messages import MsgManager

app = Flask(__name__)
auth_manager = AuthManager()
msg_manager = MsgManager(auth_manager)

def check_and_refresh_token():
"""Attempts to refresh token if expired."""

if auth_manager.is_token_expired() and not auth_manager.renew_token():
# TODO: Potential error message - Confirm
return jsonify({"error":{"message":"Failed to refresh token","status":401}})

return jsonify()

scheduler = BackgroundScheduler()
scheduler.add_job(func=check_and_refresh_token, trigger="interval", minutes=5)
scheduler.start()

# TODO: Confirm what the URL endpoint here should be - test with glific frontend.
@app.route('/login', methods=['POST'])
def login():
"""Create a new session for an existing user."""

if auth_manager.login():
return jsonify({'message': 'Login successful', 'access_token': auth_manager.access_token})

return jsonify({"error":{"message":"Invalid phone or password","status":401}})

@app.route('/send_message/<int:contact_id>', methods=['POST'])
def send_message(contact_id):
"""Creates and sends message."""

check_and_refresh_token()

message = request.json.get('message')

# TODO: Dummy return values for now
if msg_manager.send_message(contact_id, message):
return jsonify({'message': 'Send successful', "status":200})

return jsonify({"error":{"message":"Unable to send message","status":401}})

if __name__ == '__main__':
app.run(debug=True)
5 changes: 5 additions & 0 deletions run_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# run_server.py
from app.server import app

if __name__ == '__main__':
app.run(debug=True)