Merge pull request #2327 from bookwyrm-social/imports-admin

Imports admin
This commit is contained in:
Mouse Reeve 2022-11-01 20:53:58 -07:00 committed by GitHub
commit 91b935bc0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 185 additions and 2 deletions

View file

@ -48,6 +48,16 @@ class ImportJob(models.Model):
"""items that haven't been processed yet"""
return self.items.filter(fail_reason__isnull=True, book__isnull=True)
@property
def item_count(self):
"""How many books do you want to import???"""
return self.items.count()
@property
def pending_item_count(self):
"""And how many pending items??"""
return self.pending_items.count()
class ImportItem(models.Model):
"""a single line of a csv being imported"""

View file

@ -0,0 +1,23 @@
{% extends 'components/modal.html' %}
{% load i18n %}
{% block modal-title %}{% trans "Mark import as complete?" %}{% endblock %}
{% block modal-body %}
{% trans "This action cannot be un-done" %}
{% endblock %}
{% block modal-footer %}
<form name="complete-import-{{ import.id }}" action="{% url 'settings-imports-complete' import.id %}" method="POST" class="is-flex-grow-1">
{% csrf_token %}
<input type="hidden" name="id" value="{{ list.id }}">
<div class="buttons is-right is-flex-grow-1">
<button type="button" class="button" data-modal-close>
{% trans "Cancel" %}
</button>
<button class="button is-danger" type="submit">
{% trans "Confirm" %}
</button>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,86 @@
{% extends 'settings/layout.html' %}
{% load i18n %}
{% load utilities %}
{% block title %}{% trans "Imports" %}{% endblock %}
{% block header %}
{% trans "Imports" %}
{% endblock %}
{% block panel %}
<div class="block">
<div class="tabs">
<ul>
{% url 'settings-imports' as url %}
<li {% if request.path in url %}class="is-active" aria-current="page"{% endif %}>
<a href="{{ url }}">{% trans "Active" %}</a>
</li>
{% url 'settings-imports' status="complete" as url %}
<li {% if url in request.path %}class="is-active" aria-current="page"{% endif %}>
<a href="{{ url }}">{% trans "Completed" %}</a>
</li>
</ul>
</div>
</div>
<div class="table-container block content">
{% if status == "active" %}
<div class="notification is-warning">
<p>{% trans "Marking an import as complete will <em>not</em> stop it." %}</p>
</div>
{% endif %}
<table class="table is-striped is-fullwidth">
<tr>
{% url 'settings-imports' as url %}
<th>
{% trans "ID" %}
</th>
<th>
{% trans "User" %}
</th>
<th>
{% trans "Date Created" %}
</th>
<th>
{% trans "Items" %}
</th>
<th>
{% trans "Pending items" %}
</th>
{% if status == "active" %}
<th>{% trans "Actions" %}</th>
{% endif %}
</tr>
{% for import in imports %}
<tr>
<td>{{ import.id }}</td>
<td class="overflow-wrap-anywhere">
<a href="{% url 'settings-user' user.id %}">{{ import.user|username }}</a>
</td>
<td>{{ import.created_date }}</td>
<td>{{ import.item_count }}</td>
<td>{{ import.pending_item_count }}</td>
{% if status == "active" %}
<td>
{% join "complete" import.id as modal_id %}
<button type="button" data-modal-open="{{ modal_id }}" class="button is-danger">{% trans "Mark as complete" %}</button>
{% include "settings/imports/complete_import_modal.html" with id=modal_id %}
</td>
{% endif %}
</tr>
{% endfor %}
{% if not imports %}
<tr>
<td colspan="6">
<em>{% trans "No matching imports founds." %} </em>
</td>
</tr>
{% endif %}
</table>
</div>
{% include 'snippets/pagination.html' with page=users path=request.path %}
{% endblock %}

View file

@ -76,6 +76,12 @@
{% endif %}
{% if perms.edit_instance_settings %}
<h2 class="menu-label">{% trans "System" %}</h2>
<ul class="menu-list">
<li>
{% url 'settings-imports' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Imports" %}</a>
</li>
</ul>
<ul class="menu-list">
<li>
{% url 'settings-celery' as url %}

View file

@ -291,6 +291,16 @@ urlpatterns = [
views.Report.as_view(),
name="report-link",
),
re_path(
r"^settings/imports/(?P<status>(complete|active))?/?$",
views.ImportList.as_view(),
name="settings-imports",
),
re_path(
r"^settings/imports/(?P<import_id>\d+)/complete?$",
views.ImportList.as_view(),
name="settings-imports-complete",
),
re_path(
r"^settings/celery/?$", views.CeleryStatus.as_view(), name="settings-celery"
),

View file

@ -10,6 +10,7 @@ from .admin.federation import Federation, FederatedServer
from .admin.federation import AddFederatedServer, ImportServerBlocklist
from .admin.federation import block_server, unblock_server, refresh_server
from .admin.email_blocklist import EmailBlocklist
from .admin.imports import ImportList
from .admin.ip_blocklist import IPBlocklist
from .admin.invite import ManageInvites, Invite, InviteRequest
from .admin.invite import ManageInviteRequests, ignore_invite_request

View file

@ -0,0 +1,43 @@
""" manage imports """
from django.contrib.auth.decorators import login_required, permission_required
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import models
from bookwyrm.settings import PAGE_LENGTH
# pylint: disable=no-self-use
@method_decorator(login_required, name="dispatch")
@method_decorator(
permission_required("bookwyrm.moderate_user", raise_exception=True),
name="dispatch",
)
class ImportList(View):
"""admin view of imports on this server"""
def get(self, request, status="active"):
"""list of imports"""
complete = status == "complete"
imports = models.ImportJob.objects.filter(complete=complete)
paginated = Paginator(imports, PAGE_LENGTH)
page = paginated.get_page(request.GET.get("page"))
data = {
"imports": page,
"page_range": paginated.get_elided_page_range(
page.number, on_each_side=2, on_ends=1
),
"status": status,
}
return TemplateResponse(request, "settings/imports/imports.html", data)
# pylint: disable=unused-argument
def post(self, request, import_id):
"""Mark an import as complete"""
import_job = get_object_or_404(models.ImportJob, id=import_id)
import_job.complete = True
import_job.save()
return redirect("settings-imports")

View file

@ -55,8 +55,12 @@ class UserAdminList(View):
users = users.order_by(sort)
paginated = Paginator(users, PAGE_LENGTH)
page = paginated.get_page(request.GET.get("page"))
data = {
"users": paginated.get_page(request.GET.get("page")),
"users": page,
"page_range": paginated.get_elided_page_range(
page.number, on_each_side=2, on_ends=1
),
"sort": sort,
"server": server,
"status": status,