Merge pull request #569 from mouse-reeve/admin-settings

Admin settings
This commit is contained in:
Mouse Reeve 2021-01-29 17:19:45 -08:00 committed by GitHub
commit 314eddf6d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 282 additions and 14 deletions

View File

@ -195,7 +195,14 @@ class ShelfForm(CustomForm):
model = models.Shelf model = models.Shelf
fields = ['user', 'name', 'privacy'] fields = ['user', 'name', 'privacy']
class GoalForm(CustomForm): class GoalForm(CustomForm):
class Meta: class Meta:
model = models.AnnualGoal model = models.AnnualGoal
fields = ['user', 'year', 'goal', 'privacy'] fields = ['user', 'year', 'goal', 'privacy']
class SiteForm(CustomForm):
class Meta:
model = models.SiteSettings
exclude = []

View File

@ -90,13 +90,23 @@
Import books Import books
</a> </a>
</li> </li>
{% if perms.bookwyrm.create_invites or perms.bookwyrm.edit_instance_settings%}
<hr class="navbar-divider">
{% endif %}
{% if perms.bookwyrm.create_invites %} {% if perms.bookwyrm.create_invites %}
<li> <li>
<a href="/invite" class="navbar-item"> <a href="{% url 'settings-invites' %}" class="navbar-item">
Invites Invites
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% if perms.bookwyrm.edit_instance_settings %}
<li>
<a href="{% url 'settings-site' %}" class="navbar-item">
Site Configuration
</a>
</li>
{% endif %}
<hr class="navbar-divider"> <hr class="navbar-divider">
<li> <li>
<a href="/logout" class="navbar-item"> <a href="/logout" class="navbar-item">

View File

@ -0,0 +1,46 @@
{% extends 'layout.html' %}
{% block content %}
<header class="block column is-offset-one-quarter pl-1">
<h1 class="title">{% block header %}{% endblock %}</h1>
</header>
<div class="block columns">
<nav class="menu column is-one-quarter">
{% if perms.bookwyrm.create_invites %}
<h2 class="menu-label">Manage Users</h2>
<ul class="menu-list">
<li>
{% url 'settings-invites' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>Invites</a>
</li>
<li>
{% url 'settings-federation' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>Federated Servers</a>
</li>
</ul>
{% endif %}
{% if perms.bookwyrm.edit_instance_settings %}
<h2 class="menu-label">Instance Settings</h2>
<ul class="menu-list">
<li>
{% url 'settings-site' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>Site Configuration</a>
{% if url in request.path %}
<ul class="emnu-list">
<li><a href="{{ url }}#instance-info">Instance Info</a></li>
<li><a href="{{ url }}#images">Images</a></li>
<li><a href="{{ url }}#footer">Footer Content</a></li>
<li><a href="{{ url }}#registration">Registration</a></li>
</ul>
{% endif %}
</li>
</ul>
{% endif %}
</nav>
<div class="column content">
{% block panel %}{% endblock %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends 'settings/admin_layout.html' %}
{% block header %}Federated Servers{% endblock %}
{% block panel %}
<table class="table is-striped">
<tr>
<th>Server name</th>
<th>Software</th>
<th>Status</th>
</tr>
{% for server in servers %}
<tr>
<td>{{ server.server_name }}</td>
<td>{{ server.application_type }} ({{ server.application_version }})</td>
<td>{{ server.status }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -1,8 +1,8 @@
{% extends 'layout.html' %} {% extends 'settings/admin_layout.html' %}
{% block header %}Invites{% endblock %}
{% load humanize %} {% load humanize %}
{% block content %} {% block panel %}
<div class="block"> <section class="block">
<h1 class="title">Invites</h1>
<table class="table is-striped"> <table class="table is-striped">
<tr> <tr>
<th>Link</th> <th>Link</th>
@ -22,12 +22,12 @@
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </section>
<div class="block"> <section class="block">
<h2 class="title is-4">Generate New Invite</h2> <h2 class="title is-4">Generate New Invite</h2>
<form name="invite" action="/invite/" method="post"> <form name="invite" action="{% url 'settings-invites' %}" method="post">
{% csrf_token %} {% csrf_token %}
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
@ -46,5 +46,5 @@
<button class="button is-primary" type="submit">Create Invite</button> <button class="button is-primary" type="submit">Create Invite</button>
</form> </form>
</div> </section>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,84 @@
{% extends 'settings/admin_layout.html' %}
{% block header %}Site Configuration{% endblock %}
{% block panel %}
<form action="{% url 'settings-site' %}" method="POST" class="content">
{% csrf_token %}
<section class="block" id="instance-info">
<h2 class="title is-4">Instance Info</h2>
<div class="control">
<label class="label" for="id_name">Instance Name:</label>
{{ site_form.name }}
</div>
<div class="control">
<label class="label" for="id_instance_tagline">Tagline:</label>
{{ site_form.instance_tagline }}
</div>
<div class="control">
<label class="label" for="id_instance_description">Instance description:</label>
{{ site_form.instance_description }}
</div>
<div class="control">
<label class="label" for="id_code_of_conduct">Code of conduct:</label>
{{ site_form.code_of_conduct }}
</div>
</section>
<hr aria-hidden="true">
<section class="block" id="images">
<h2 class="title is-4">Images</h2>
<div class="field is-grouped">
<div class="control">
<label class="label" for="id_logo">Logo:</label>
{{ site_form.logo }}
</div>
<div class="control">
<label class="label" for="id_logo_small">Logo small:</label>
{{ site_form.logo_small }}
</div>
<div class="control">
<label class="label" for="id_favicon">Favicon:</label>
{{ site_form.favicon }}
</div>
</div>
</section>
<hr aria-hidden="true">
<section class="block" id="footer">
<h2 class="title is-4">Footer Content</h2>
<div class="control">
<label class="label" for="id_support_link">Support link:</label>
<input type="text" name="support_link" maxlength="255" class="input" id="id_support_link" placeholder="https://www.patreon.com/bookwyrm"{% if site.support_link %} value="{{ site.support_link }}"{% endif %}>
</div>
<div class="control">
<label class="label" for="id_support_title">Support title:</label>
<input type="text" name="support_title" maxlength="100" class="input" id="id_support_title" placeholder="Patreon"{% if site.support_title %} value="{{ site.support_title }}"{% endif %}>
</div>
<div class="control">
<label class="label" for="id_admin_email">Admin email:</label>
{{ site_form.admin_email }}
</div>
</section>
<hr aria-hidden="true">
<section class="block" id="registration">
<h2 class="title is-4">Registration</h2>
<div class="control">
<label class="label" for="id_allow_registration">Allow registration:
{{ site_form.allow_registration }}
</div>
<div class="control">
<label class="label" for="id_registration_closed_text">Registration closed text:</label>
{{ site_form.registration_closed_text }}
</div>
</section>
<footer class="block">
<button class="button is-primary" type="submit">Save Changes</button>
</footer>
</form>
{% endblock %}

View File

@ -0,0 +1,29 @@
''' test for app action functionality '''
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
class FederationViews(TestCase):
''' every response to a get request, html or json '''
def setUp(self):
''' we need basic test data and mocks '''
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
'mouse@local.com', 'mouse@mouse.mouse', 'password',
local=True, localname='mouse')
def test_federation_page(self):
''' there are so many views, this just makes sure it LOADS '''
view = views.Federation.as_view()
request = self.factory.get('')
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
self.assertEqual(result.template_name, 'settings/federation.html')
self.assertEqual(result.status_code, 200)

View File

@ -44,5 +44,5 @@ class InviteViews(TestCase):
request.user.is_superuser = True request.user.is_superuser = True
result = view(request) result = view(request)
self.assertIsInstance(result, TemplateResponse) self.assertIsInstance(result, TemplateResponse)
self.assertEqual(result.template_name, 'manage_invites.html') self.assertEqual(result.template_name, 'settings/manage_invites.html')
self.assertEqual(result.status_code, 200) self.assertEqual(result.status_code, 200)

View File

@ -49,8 +49,13 @@ urlpatterns = [
re_path(r'^password-reset/(?P<code>[A-Za-z0-9]+)/?$', re_path(r'^password-reset/(?P<code>[A-Za-z0-9]+)/?$',
views.PasswordReset.as_view()), views.PasswordReset.as_view()),
# invites # admin
re_path(r'^invite/?$', views.ManageInvites.as_view()), re_path(r'^settings/site-settings',
views.Site.as_view(), name='settings-site'),
re_path(r'^settings/federation',
views.Federation.as_view(), name='settings-federation'),
re_path(r'^settings/invites/?$',
views.ManageInvites.as_view(), name='settings-invites'),
re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', views.Invite.as_view()), re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', views.Invite.as_view()),
# landing pages # landing pages

View File

@ -5,6 +5,7 @@ from .block import Block, unblock
from .books import Book, EditBook, Editions from .books import Book, EditBook, Editions
from .books import upload_cover, add_description, switch_edition, resolve_book from .books import upload_cover, add_description, switch_edition, resolve_book
from .error import not_found_page, server_error_page from .error import not_found_page, server_error_page
from .federation import Federation
from .feed import DirectMessage, Feed, Replies, Status from .feed import DirectMessage, Feed, Replies, Status
from .follow import follow, unfollow from .follow import follow, unfollow
from .follow import accept_follow_request, delete_follow_request, handle_accept from .follow import accept_follow_request, delete_follow_request, handle_accept
@ -24,6 +25,7 @@ from .search import Search
from .shelf import Shelf from .shelf import Shelf
from .shelf import user_shelves_page, create_shelf, delete_shelf from .shelf import user_shelves_page, create_shelf, delete_shelf
from .shelf import shelve, unshelve from .shelf import shelve, unshelve
from .site import Site
from .status import CreateStatus, DeleteStatus from .status import CreateStatus, DeleteStatus
from .updates import Updates from .updates import Updates
from .user import User, EditUser, Followers, Following from .user import User, EditUser, Followers, Following

View File

@ -0,0 +1,24 @@
''' manage federated servers '''
from django.contrib.auth.decorators import login_required, permission_required
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import models
# pylint: disable= no-self-use
@method_decorator(login_required, name='dispatch')
@method_decorator(
permission_required('bookwyrm.control_federation', raise_exception=True),
name='dispatch')
class Federation(View):
''' what servers do we federate with '''
def get(self, request):
''' edit form '''
servers = models.FederatedServer.objects.all()
data = {
'title': 'Federated Servers',
'servers': servers
}
return TemplateResponse(request, 'settings/federation.html', data)

View File

@ -24,7 +24,7 @@ class ManageInvites(View):
user=request.user).order_by('-created_date'), user=request.user).order_by('-created_date'),
'form': forms.CreateInviteForm(), 'form': forms.CreateInviteForm(),
} }
return TemplateResponse(request, 'manage_invites.html', data) return TemplateResponse(request, 'settings/manage_invites.html', data)
def post(self, request): def post(self, request):
''' creates an invite database entry ''' ''' creates an invite database entry '''
@ -36,7 +36,7 @@ class ManageInvites(View):
invite.user = request.user invite.user = request.user
invite.save() invite.save()
return redirect('/invite') return redirect('/settings/invites')
class Invite(View): class Invite(View):

40
bookwyrm/views/site.py Normal file
View File

@ -0,0 +1,40 @@
''' manage site settings '''
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import forms, models
# pylint: disable= no-self-use
@method_decorator(login_required, name='dispatch')
@method_decorator(
permission_required(
'bookwyrm.edit_instance_settings', raise_exception=True),
name='dispatch')
class Site(View):
''' manage things like the instance name '''
def get(self, request):
''' edit form '''
site = models.SiteSettings.objects.get()
data = {
'title': 'Site Settings',
'site_form': forms.SiteForm(instance=site)
}
return TemplateResponse(request, 'settings/site.html', data)
def post(self, request):
''' edit the site settings '''
site = models.SiteSettings.objects.get()
form = forms.SiteForm(request.POST, instance=site)
if not form.is_valid():
data = {
'title': 'Site Settings',
'site_form': form
}
return TemplateResponse(request, 'settings/site.html', data)
form.save()
return redirect('settings-site')