Add multiuser support

Currently, this uses anonymous sessions. You log in to your instance, and you
get associated with a session. Your client information and account information
are persisted (created only if needed, reattached if not). Passwords are never
stored, only access tokens.
This commit is contained in:
Jason McBrayer 2018-04-24 14:49:43 -04:00
parent 5c48180a7c
commit 267e94077f
5 changed files with 62 additions and 19 deletions

View File

@ -15,7 +15,7 @@ Brutaldon is not ready for use yet.
* [X] Single user read-only access; log in and read home timeline
* [X] Fix edge cases of toot display (CW, media, boosts)
* [ ] Multi-user, multi-instance support
* [X] Multi-user, multi-instance support
* [ ] Add support for reading local and federated timelines, notifications, favorites, threads
* [ ] Add support for tag timelines
* [ ] Add support for viewing profiles

View File

@ -3,7 +3,7 @@ from django import forms
class LoginForm(forms.Form):
instance = forms.CharField(label="Instance",
max_length=256)
username = forms.CharField(label="Username",
username = forms.CharField(label="Email",
max_length=256)
password = forms.CharField(widget=forms.PasswordInput())

View File

@ -0,0 +1,18 @@
# Generated by Django 2.0.4 on 2018-04-24 18:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('brutaldon', '0003_auto_20180424_1255'),
]
operations = [
migrations.AlterField(
model_name='account',
name='username',
field=models.EmailField(max_length=254),
),
]

View File

@ -11,7 +11,7 @@ class Client(models.Model):
return self.name + ": " + self.api_base_id
class Account(models.Model):
username = models.CharField(max_length=80)
username = models.EmailField()
django_user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, null=True)
access_token = models.TextField(null=True, blank=True)
client= models.ForeignKey(Client, models.SET_NULL, null=True)

View File

@ -4,13 +4,19 @@ from brutaldon.forms import LoginForm
from brutaldon.models import Client, Account
from mastodon import Mastodon
import datetime
from urllib import parse
def home(request):
now = datetime.datetime.now()
if not (request.session.has_key('instance') and
request.session.has_key('username')):
return redirect(login)
try:
client = Client.objects.all()[0]
user = Account.objects.all()[0]
except:
client = Client.objects.get(api_base_id=request.session['instance'])
user = Account.objects.get(username=request.session['username'])
except (Client.DoesNotExist, Client.MultipleObjectsReturned,
Account.DoesNotExist, Account.MultipleObjectsReturned):
return redirect(login)
mastodon = Mastodon(
@ -31,10 +37,22 @@ def login(request):
elif request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
api_base_url = form.cleaned_data['instance'] # Fixme, make sure this is url
api_base_url = form.cleaned_data['instance']
# Fixme, make sure this is url
tmp_base = parse.urlparse(api_base_url.lower())
if tmp_base.netloc == '':
api_base_url = parse.urlunparse(('https', tmp_base.path,
'','','',''))
else:
api_base_url = api_base_url.lower()
request.session['instance'] = api_base_url
username = form.cleaned_data['username']
password = form.cleaned_data['password']
try:
client = Client.objects.get(api_base_id=api_base_url)
except (Client.DoesNotExist, Client.MultipleObjectsReturned):
(client_id, client_secret) = Mastodon.create_app('brutaldon',
api_base_url=api_base_url)
client = Client(
@ -44,19 +62,26 @@ def login(request):
client.save()
mastodon = Mastodon(
client_id = client_id,
client_secret = client_secret,
client_id = client.client_id,
client_secret = client.client_secret,
api_base_url = api_base_url)
access_token = mastodon.log_in(username,
password)
try:
account = Account.objects.get(username=username, client_id=client.id)
account.access_token = access_token
except (Account.DoesNotExist, Account.MultipleObjectsReturned):
account = Account(
username = username,
access_token = access_token)
access_token = access_token,
client = client)
account.save()
request.session['username'] = username
return redirect(home)
else:
return redirect(error)
return render(request, 'setup/login.html', {'form': form})
def error(request):
return render('error.html', { 'error': "Not logged in yet."})