tfb-groupme-bridge/tfbbridge/bridge/views.py

411 lines
14 KiB
Python

from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import redirect, render
from django.urls import reverse
from .models import Organization
import requests
import pickle
import qrcode
import json
import random
from itertools import chain
from .utils import *
from .groupme import GroupMe
bot_name = "tfbbot"
auth_link = "https://oauth.groupme.com/oauth/authorize?client_id=KbStJZciPGivvLuTN9XX6aXf6NHVcxDSiVR0wRC0cqVDuDfG"
def login(request):
return redirect(auth_link)
def add_organization_flow_select(request):
user_group_data = from_pickle(request.session["groupme_groups_pickle"])
user_group_data = user_group_data["response"]
if request.method == "GET":
rendered_groups = []
rendered_users = []
for group in user_group_data:
our_id = request.session["groupme_id"]
for user in group["members"]: # check if we're an admin
if user["user_id"] == our_id:
if "admin" in user["roles"]: # we are an admin
rendered_groups.append({
"name": group["name"],
"id": group["group_id"]
})
for user in group["members"]:
rendered_users.append({
"name": user["name"],
"id": user["user_id"]
})
break
rendered_users = remove_dup_dict_in_list(rendered_users)
# sort users by name
rendered_users = sorted(rendered_users, key=lambda x: x["name"].lower())
context = {
"request": request,
"title": "Add organization",
"groups": rendered_groups,
"users": rendered_users
}
return render(request, "create_organization.html", context)
elif request.method == "POST":
name = request.POST["name"]
users = [i[2:] for i in request.POST.keys() if i.startswith("u_")]
groups = [i[2:] for i in request.POST.keys() if i.startswith("g_")]
group_name_mapping = from_pickle(request.session["group_name_mapping"])
org = Organization()
org.owner = request.session["groupme_id"]
org.name = name
org.trusted_users = ""
org.channel_info = ""
org.save()
group_data_collected = []
for group in groups:
group_data = { "gid": group }
data = {
"bot": {
"name": bot_name,
"group_id": group,
"active": True,
"callback_url": "https://marching.beepboop.systems/groupme/organization/{}/callback/{}".format(
org.id,
str(random.randint(1, 100000))
),
}
}
r = requests.post(
"https://api.groupme.com/v3/bots?token={}".format(
request.session["groupme_access_token"]
),
data=json.dumps(data),
headers={"Content-Type": "application/json"},
)
data = r.json()
print(r.url)
group_data["bot_id"] = data["response"]["bot"]["bot_id"]
group_data["name"] = group_name_mapping[group_data["gid"]]
group_data["role"] = "trusted"
group_data_collected.append(group_data)
user_data_collected = []
user_name_mappings = from_pickle(request.session["user_name_mapping"])
for user in users:
try:
username = user_name_mappings[user]
except KeyError:
username = "unknown"
user_data = { "uid": user, "role": "trusted", "name": username, "number_messages": 0 }
user_data_collected.append(user_data)
org.trusted_users = to_pickle(user_data_collected)
org.channel_info = to_pickle(group_data_collected)
org.save()
return redirect(reverse("view_organization", kwargs={"org_id": org.id}))
def handle_oauth(request):
request.session["token"] = request.GET.get('access_token')
api = GroupMe(request.session["token"])
me = api.me()
groups = api.groups()
request.session["groups"] = to_pickle(groups)
request.session["logged_in"] = "yes"
users = list(set(chain(
[group.members for group in groups]
)))
request.session["users"] = to_pickle(users)
try:
if request.session["needs_redirect"]:
response = redirect(reverse(request.session["needs_redirect"]))
del request.session["needs_redirect"]
return response
except KeyError:
pass
return redirect(reverse("index"))
def index(request):
if "logged_in" in request.session:
orgs = Organization.objects.filter(owner=request.session["groupme_id"])
return render(request, "index_auth.html", {
"title": "Home",
"request": request,
"organizations": orgs,
})
else:
return render(request, "index_unauth.html", {
"title": "Home",
})
def refresh_group_data(request):
return redirect(reverse("handle_oauth") + "?access_token={}".format(
request.session["groupme_access_token"]
))
def logout(request):
if "logged_in" in request.session:
request.session.flush()
return render(request, "logged_out.html")
else:
return redirect(index)
def view_organization(request, org_id):
org = get_org_by_id(org_id)
scheme = 'https' if request.is_secure() else 'http'
hostname = request.get_host()
if request.session["groupme_id"] == org.owner:
org_channel_info = from_pickle(org.channel_info)
org_trusted_users = from_pickle(org.trusted_users)
return render(request, "view_organization.html", {
"request": request,
"org": org,
"hostname": hostname,
"scheme": scheme,
"channels": org_channel_info,
"users": org_trusted_users,
})
else:
pass # blow up
def qr_code(request, org_id):
org = get_org_by_id(org_id)
scheme = 'https' if request.is_secure() else 'http'
hostname = request.get_host()
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data("{}://{}{}".format(
scheme,
hostname,
reverse('add_channel_to_organization', args=[org.id]),
))
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
resp = HttpResponse(
headers={
"Content-Type": "image/png",
}
)
img.save(resp)
return resp
def add_channel_to_organization(request, org_id, trusted=False):
if not request.session["groupme_access_token"]:
request.session["needs_redirect"] = "add_channel_to_organization"
return redirect(reverse("login"))
org = get_org_by_id(org_id)
if request.method == "GET":
user_group_data = from_pickle(request.session["groupme_groups_pickle"])["response"]
our_id = request.session["groupme_id"]
groups_we_admin = []
for group in user_group_data:
for user in group["members"]: # check if we're an admin
if user["user_id"] == our_id:
if "admin" in user["roles"]: # we are an admin
groups_we_admin.append(group)
return render(request, "add_channel_to_organization.html", {
"groups": groups_we_admin,
"org": org,
"request": request,
"trusted": trusted,
})
elif request.method == "POST":
group_name_mapping = from_pickle(request.session["group_name_mapping"])
org = get_org_by_id(org_id)
groups = [i[2:] for i in request.POST.keys() if i.startswith("g_")]
org_group_info = pickle.loads(bytes.fromhex(org.channel_info))
if not trusted:
for group in org_group_info:
if group["gid"] in groups and group["role"] != "trusted":
# prune the groups
groups.remove(group["gid"])
else:
for index, group in enumerate(org_group_info):
if group["gid"] in groups:
org_group_info[index]["role"] = "trusted"
to_add = []
# these are the unique groups
for group in groups:
if not trusted:
data = {
"bot": {
"name": bot_name,
"group_id": group,
"active": True,
}
}
else:
data = {
"bot": {
"name": bot_name,
"group_id": group,
"active": True,
"callback_url": "https://marching.beepboop.systems/groupme/organization/{}/callback/{}".format(
org.id,
str(random.randint(1, 100000))
),
}
}
r = requests.post(
"https://api.groupme.com/v3/bots?token={}".format(
request.session["groupme_access_token"]
),
data=json.dumps(data),
headers={"Content-Type": "application/json"},
)
data = r.json()
if not trusted:
to_add.append({
"gid": group,
"bot_id": data["response"]["bot"]["bot_id"],
"name": group_name_mapping[group],
"role": "following",
})
else:
to_add.append({
"gid": group,
"bot_id": data["response"]["bot"]["bot_id"],
"name": group_name_mapping[group],
"role": "trusted",
})
org_group_info += to_add
org.channel_info = pickle.dumps(org_group_info).hex()
org.save()
if request.session["groupme_id"] == org.owner:
return redirect(reverse('view_organization', args=[org.id]))
else:
return render(request, "group_add_succeed.html", {
"request": request
})
def add_trusted_channel(request, org_id):
return add_channel_to_organization(request, org_id, trusted=True)
def delete_channel(request, org_id, chan):
org = Organization.objects.filter(id__exact=org_id)[0]
org_group_info = pickle.loads(bytes.fromhex(org.channel_info))
print(org_group_info)
for index, channel in enumerate(org_group_info):
print(index, channel)
if channel["gid"] == chan:
org_group_info.pop(index)
break
org.channel_info = pickle.dumps(org_group_info).hex()
org.save()
return redirect(reverse('view_organization', args=[org.id]))
def demote_channel(request, org_id, chan):
org = get_org_by_id(org_id)
org_group_info = from_pickle(org.channel_info)
for index, channel in enumerate(org_group_info):
print(index, channel)
if channel["gid"] == chan:
org_group_info[index]["role"] = "following"
break
org.channel_info = to_pickle(org_group_info)
org.save()
return redirect(reverse('view_organization', args=[org.id]))
def add_trusted_user(request, org_id):
org = get_org_by_id(org_id)
org_trusted_users = from_pickle(org.trusted_users)
user_group_data = from_pickle(request.session["groupme_groups_pickle"])
user_group_data = user_group_data["response"]
rendered_users = []
for group in user_group_data:
our_id = request.session["groupme_id"]
for user in group["members"]: # check if we're an admin
if user["user_id"] == our_id:
if "admin" in user["roles"]: # we are an admin
for user in group["members"]:
rendered_users.append({
"name": user["name"],
"id": user["user_id"]
})
break
rendered_users = remove_dup_dict_in_list(rendered_users)
if request.method == "GET":
return render(request, "add_user.html", {
"request": request,
"users": rendered_users,
"org": org,
})
elif request.method == "POST":
users = [i[2:] for i in request.POST.keys() if i.startswith("u_")]
user_name_mappings = pickle.loads(bytes.fromhex(request.session["user_name_mapping"]))
for user in users:
try:
username = user_name_mappings[user]
except KeyError:
username = "unknown"
user_data = { "uid": user, "role": "trusted", "name": username, "number_messages": 0 }
org_trusted_users.append(user_data)
org.trusted_users = pickle.dumps(org_trusted_users).hex()
org.save()
return redirect(reverse('view_organization', args=[org.id]))
def remove_user(request, org_id, user):
org = get_org_by_id(org_id)
org_trusted_users = from_pickle(org.trusted_users)
for index, tuser in enumerate(org_trusted_users):
print(index, tuser)
if tuser["uid"] == user:
org_trusted_users.pop(index)
break
org.trusted_users = to_pickle(org_trusted_users)
org.save()
return redirect(reverse('view_organization', args=[org.id]))