diff --git a/shell.nix b/shell.nix
index 9c50102..578461c 100644
--- a/shell.nix
+++ b/shell.nix
@@ -4,5 +4,6 @@
nativeBuildInputs = with pkgs; [
buildPackages.python311Packages.django
buildPackages.python311Packages.requests
+ buildPackages.python311Packages.qrcode
];
-}
\ No newline at end of file
+}
diff --git a/tfbbridge/.gitignore b/tfbbridge/.gitignore
index 2b76056..49ef255 100644
--- a/tfbbridge/.gitignore
+++ b/tfbbridge/.gitignore
@@ -1,2 +1 @@
db.sqlite3
-manage.py
\ No newline at end of file
diff --git a/tfbbridge/bridge/admin.py b/tfbbridge/bridge/admin.py
index 4575273..b1e5e57 100644
--- a/tfbbridge/bridge/admin.py
+++ b/tfbbridge/bridge/admin.py
@@ -1,10 +1,5 @@
from django.contrib import admin
-from .models import Organization, Group
+from .models import Organization
-@admin.register(Organization)
-class OrganizationAdmin(admin.ModelAdmin):
- exclude = ('_sender_url', '_receiver_url')
- readonly_fields = ('add_sending_group', 'add_receiving_group', )
-
-admin.site.register(Group)
\ No newline at end of file
+admin.site.register(Organization)
diff --git a/tfbbridge/bridge/models.py b/tfbbridge/bridge/models.py
index 4346fae..20f3163 100644
--- a/tfbbridge/bridge/models.py
+++ b/tfbbridge/bridge/models.py
@@ -1,36 +1,9 @@
from django.db import models
-import uuid
-
-def get_uuid():
- return uuid.uuid4().hex
class Organization(models.Model):
name = models.CharField(
max_length=256,
)
- _sender_url = models.CharField(
- max_length=256,
- default = get_uuid
- )
- _receiver_url = models.CharField(
- max_length=256,
- default = get_uuid
- )
-
- @property
- def add_sending_group(self):
- return "https://tfb.beepboop.systems/groupme/add/send/{}".format(
- self._sender_url
- )
- @property
- def add_receiving_group(self):
- return "https://tfb.beepboop.systems/groupme/add/recv/{}".format(
- self._receiver_url
- )
-
-class Group(models.Model):
- name = models.CharField(max_length=256)
- group_id = models.CharField(max_length=256)
- bot_id = models.CharField(max_length=256)
- can_send_notices = models.BooleanField()
- belongs_to = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True)
\ No newline at end of file
+ owner = models.CharField(max_length=256)
+ trusted_users = models.TextField() # either json or empty
+ channel_info = models.TextField() # either json or empty
diff --git a/tfbbridge/bridge/templates/add_channel_to_organization.html b/tfbbridge/bridge/templates/add_channel_to_organization.html
new file mode 100644
index 0000000..69dbd83
--- /dev/null
+++ b/tfbbridge/bridge/templates/add_channel_to_organization.html
@@ -0,0 +1,31 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+
Add groups to "{{ org.name }}"
+
+{% if trusted %}
+
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/add_user.html b/tfbbridge/bridge/templates/add_user.html
new file mode 100644
index 0000000..6d4bf2d
--- /dev/null
+++ b/tfbbridge/bridge/templates/add_user.html
@@ -0,0 +1,39 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+Add a trusted user
+
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/base.html b/tfbbridge/bridge/templates/base.html
new file mode 100644
index 0000000..05d9745
--- /dev/null
+++ b/tfbbridge/bridge/templates/base.html
@@ -0,0 +1,41 @@
+
+
+
+ {% if title %}
+ {{ title }} - tfb-groupme-bridge
+ {% else %}
+ tfb-groupme-bridge
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+
+ {% block 'body' %}
+ {% endblock %}
+
+
+
diff --git a/tfbbridge/bridge/templates/create_organization.html b/tfbbridge/bridge/templates/create_organization.html
new file mode 100644
index 0000000..4102e36
--- /dev/null
+++ b/tfbbridge/bridge/templates/create_organization.html
@@ -0,0 +1,74 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+Create a new organization
+
+You will be the administrator of this organization. If you don't want to be, do not create the organization under your account — use someone else's! You won't be able to transfer ownership later , so make a wise decision now.
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/group_add_succeed.html b/tfbbridge/bridge/templates/group_add_succeed.html
new file mode 100644
index 0000000..d0332f1
--- /dev/null
+++ b/tfbbridge/bridge/templates/group_add_succeed.html
@@ -0,0 +1,8 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+Group added
+
+Thanks!
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/index_auth.html b/tfbbridge/bridge/templates/index_auth.html
new file mode 100644
index 0000000..864f32f
--- /dev/null
+++ b/tfbbridge/bridge/templates/index_auth.html
@@ -0,0 +1,27 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+Welcome, {{ request.session.groupme_name }}
+
+Available actions
+
+
+
+{% if organizations|length > 0 %}
+Your organizations
+
+{% else %}
+Your organizations
+
+You don't seem to have any organizations — maybe create one ?
+{% endif %}
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/index_unauth.html b/tfbbridge/bridge/templates/index_unauth.html
new file mode 100644
index 0000000..a95faa9
--- /dev/null
+++ b/tfbbridge/bridge/templates/index_unauth.html
@@ -0,0 +1,6 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+tfb-groupme-bridge
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/logged_out.html b/tfbbridge/bridge/templates/logged_out.html
new file mode 100644
index 0000000..0ff706d
--- /dev/null
+++ b/tfbbridge/bridge/templates/logged_out.html
@@ -0,0 +1,12 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+Logged out
+
+You've been logged out.
+
+
+
+{% endblock %}
diff --git a/tfbbridge/bridge/templates/view_organization.html b/tfbbridge/bridge/templates/view_organization.html
new file mode 100644
index 0000000..ab2c607
--- /dev/null
+++ b/tfbbridge/bridge/templates/view_organization.html
@@ -0,0 +1,79 @@
+{% extends 'base.html' %}
+{% block 'body' %}
+
+{{ org.name }}
+
+Channels
+
+
+
+ Name
+ Level
+ Actions
+
+
+
+ {% for channel in channels %}
+
+ {{ channel.name }}
+ {{ channel.role }}
+
+
+
+ {% if channel.role == "trusted" %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% endfor %}
+
+
+
+
+
+Trusted Users
+
+
+
+
+ Name
+ Sent messages
+ Actions
+
+
+
+ {% for user in users %}
+
+ {{ user.name }}
+ {{ user.number_messages }}
+
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/tfbbridge/bridge/urls.py b/tfbbridge/bridge/urls.py
index a9641c2..96c7e3e 100644
--- a/tfbbridge/bridge/urls.py
+++ b/tfbbridge/bridge/urls.py
@@ -3,6 +3,17 @@ from . import views
urlpatterns = [
path("", views.index, name="index"),
+ path("logout", views.logout, name="logout"),
+ path("login", views.login, name="login"),
path("oauth_callback", views.handle_oauth, name="handle_oauth"),
- path("add/send/", views.add_sending_group, name="add_sending_group"),
-]
\ No newline at end of file
+ path("refresh_group_data", views.refresh_group_data, name="refresh_group_data"),
+ path("add/organization", views.add_organization_flow_select, name="add_organization_flow_select"),
+ path("organization/", views.view_organization, name="view_organization"),
+ path("organization//add_channel", views.add_channel_to_organization, name="add_channel_to_organization"),
+ path("organization//add_trusted_channel", views.add_trusted_channel, name="add_trusted_channel"),
+ path("organization//add_trusted_user", views.add_trusted_user, name="add_trusted_user"),
+ path("organization//qr_code", views.qr_code, name="qr_code"),
+ path("organization//delete_channel/", views.delete_channel, name="delete_channel"),
+ path("organization//demote_channel/", views.demote_channel, name="demote_channel"),
+ path("organization//remove_user/", views.remove_user, name="remove_user"),
+]
diff --git a/tfbbridge/bridge/views.py b/tfbbridge/bridge/views.py
index 0cbb795..248f13e 100644
--- a/tfbbridge/bridge/views.py
+++ b/tfbbridge/bridge/views.py
@@ -1,35 +1,443 @@
from django.http import HttpResponse, HttpResponseBadRequest
-from django.shortcuts import redirect
+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
-auth_link = "https://oauth.groupme.com/oauth/authorize?client_id=qAAAc8GSUlTA8C3Ypo9CMiFQwQCQnU8zPU5KGEtz3FYHDqP5"
+bot_name = "tfbbot"
+auth_link = "https://oauth.groupme.com/oauth/authorize?client_id=KbStJZciPGivvLuTN9XX6aXf6NHVcxDSiVR0wRC0cqVDuDfG"
-def index(request):
- return HttpResponse("Hello, world. You're at the polls index.")
+def login(request):
+ return redirect(auth_link)
-def handle_send_requests(token, org_id):
- # firstly, check what organization the org_id belongs to
- matching = Organization.objects.filter(_sender_url = org_id)
- if matching == []:
- return HttpResponseBadRequest # this is a fake org_id
+def add_organization_flow_select(request):
+ user_group_data = pickle.loads(
+ bytes.fromhex(
+ 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
+
+ # remove duplicate users
+ # https://stackoverflow.com/questions/9427163/remove-duplicate-dict-in-list-in-python
+ rendered_users = [i for n, i in enumerate(rendered_users) if i not in rendered_users[n + 1:]]
+
+ # 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 = pickle.loads(
+ bytes.fromhex(
+ 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 = 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 }
+ user_data_collected.append(user_data)
+
+ org.trusted_users = pickle.dumps(user_data_collected).hex()
+ org.channel_info = pickle.dumps(group_data_collected).hex()
+ org.save()
+
+ return redirect(reverse("view_organization", kwargs={"org_id": org.id}))
def handle_oauth(request):
- token = request.GET.get('access_token')
+ request.session["groupme_access_token"] = request.GET.get('access_token')
+
+ r = requests.get("https://api.groupme.com/v3/users/me?token={}".format(
+ request.session["groupme_access_token"]
+ ))
+
+ data = r.json()
+ request.session["groupme_id"] = data["response"]["id"]
+ request.session["groupme_name"] = data["response"]["name"]
+
+ r = requests.get("https://api.groupme.com/v3/groups?token={}&per_page=200".format(
+ request.session["groupme_access_token"]
+ ))
+
+ request.session["groupme_groups_pickle"] = pickle.dumps(r.json()).hex()
+ request.session["logged_in"] = "yes"
+
+ group_name_mapping = {}
+ for group in r.json()["response"]:
+ group_name_mapping[group["id"]] = group["name"]
+ request.session["group_name_mapping"] = pickle.dumps(group_name_mapping).hex()
+
+ user_name_mapping = {}
+ for group in r.json()["response"]:
+ for user in group["members"]:
+ user_name_mapping[user["id"]] = user["name"]
+ user_name_mapping[data["response"]["id"]] = data["response"]["name"]
+ request.session["user_name_mapping"] = pickle.dumps(user_name_mapping).hex()
+
try:
- request_type = request.session["type"]
- organization_id = request.session["id"]
+ if request.session["needs_redirect"]:
+ response = redirect(reverse(request.session["needs_redirect"]))
+ del request.session["needs_redirect"]
+ return response
except KeyError:
- return HttpResponseBadRequest
+ pass
- if request_type == "send":
- return handle_send_requests(token, organization_id)
+ return redirect(reverse("index"))
- return HttpResponse(token)
+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 add_sending_group(request, url_id):
- # first part -- authenticate with the GroupMe api
- request.session['type'] = "send"
- request.session['id'] = url_id
+def refresh_group_data(request):
+ return redirect(reverse("handle_oauth") + "?access_token={}".format(
+ request.session["groupme_access_token"]
+ ))
- return redirect(auth_link)
\ No newline at end of file
+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 = Organization.objects.filter(id__exact=org_id)[0]
+ scheme = 'https' if request.is_secure() else 'http'
+ hostname = request.get_host()
+
+ if request.session["groupme_id"] == org.owner:
+ org_channel_info = pickle.loads(bytes.fromhex(org.channel_info))
+ org_trusted_users = pickle.loads(bytes.fromhex(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 = Organization.objects.filter(id__exact=org_id)[0]
+ 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 = Organization.objects.filter(id__exact=org_id)[0]
+
+ if request.method == "GET":
+ user_group_data = pickle.loads(
+ bytes.fromhex(
+ 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 = pickle.loads(
+ bytes.fromhex(
+ request.session["group_name_mapping"]
+ ))
+ org = Organization.objects.filter(id__exact=org_id)[0]
+ 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"},
+ )
+
+ print(r)
+ 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 = Organization.objects.filter(id__exact=org_id)[0]
+ org_group_info = pickle.loads(bytes.fromhex(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 = pickle.dumps(org_group_info).hex()
+ org.save()
+
+ return redirect(reverse('view_organization', args=[org.id]))
+
+def add_trusted_user(request, org_id):
+ org = Organization.objects.filter(id__exact=org_id)[0]
+ org_trusted_users = pickle.loads(bytes.fromhex(org.trusted_users))
+ user_group_data = pickle.loads(
+ bytes.fromhex(
+ 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
+
+ # remove duplicate users
+ # https://stackoverflow.com/questions/9427163/remove-duplicate-dict-in-list-in-python
+ rendered_users = [i for n, i in enumerate(rendered_users) if i not in rendered_users[n + 1:]]
+
+ 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 = Organization.objects.filter(id__exact=org_id)[0]
+ org_trusted_users = pickle.loads(bytes.fromhex(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 = pickle.dumps(org_trusted_users).hex()
+ org.save()
+
+ return redirect(reverse('view_organization', args=[org.id]))
diff --git a/tfbbridge/manage.py b/tfbbridge/manage.py
new file mode 100644
index 0000000..88f8398
--- /dev/null
+++ b/tfbbridge/manage.py
@@ -0,0 +1,21 @@
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tfb.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tfbbridge/tfb/settings.py b/tfbbridge/tfb/settings.py
index f2869a9..1c82c0d 100644
--- a/tfbbridge/tfb/settings.py
+++ b/tfbbridge/tfb/settings.py
@@ -25,8 +25,8 @@ SECRET_KEY = 'django-insecure-%4qs)a3%&$ykwuu5d$0%^=8u1)b=t=t+vgo!rxvrq1z9+7)w1z
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
-ALLOWED_HOSTS = ["10.100.0.2"]
-CSRF_TRUSTED_ORIGINS = ["https://tfb.beepboop.systems"]
+ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
+CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000"]
# Application definition