commit
314eddf6d4
@ -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 = []
|
||||||
|
@ -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">
|
||||||
|
46
bookwyrm/templates/settings/admin_layout.html
Normal file
46
bookwyrm/templates/settings/admin_layout.html
Normal 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 %}
|
21
bookwyrm/templates/settings/federation.html
Normal file
21
bookwyrm/templates/settings/federation.html
Normal 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 %}
|
@ -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 %}
|
84
bookwyrm/templates/settings/site.html
Normal file
84
bookwyrm/templates/settings/site.html
Normal 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 %}
|
29
bookwyrm/tests/views/test_federation.py
Normal file
29
bookwyrm/tests/views/test_federation.py
Normal 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)
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
24
bookwyrm/views/federation.py
Normal file
24
bookwyrm/views/federation.py
Normal 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)
|
@ -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
40
bookwyrm/views/site.py
Normal 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')
|
Loading…
x
Reference in New Issue
Block a user