mirror of
https://github.com/jointakahe/takahe.git
synced 2024-11-22 07:10:59 +00:00
User admin and LD schema fixes
This commit is contained in:
parent
1bcdff79e7
commit
45c6978bc3
13 changed files with 189 additions and 23 deletions
|
@ -659,7 +659,7 @@ class Post(StatorModel):
|
|||
if update or created:
|
||||
post.content = data["content"]
|
||||
post.summary = data.get("summary")
|
||||
post.sensitive = data.get("as:sensitive", False)
|
||||
post.sensitive = data.get("sensitive", False)
|
||||
post.url = data.get("url")
|
||||
post.published = parse_ld_date(data.get("published"))
|
||||
post.edited = parse_ld_date(data.get("updated"))
|
||||
|
@ -670,7 +670,7 @@ class Post(StatorModel):
|
|||
if tag["type"].lower() == "mention":
|
||||
mention_identity = Identity.by_actor_uri(tag["href"], create=True)
|
||||
post.mentions.add(mention_identity)
|
||||
elif tag["type"].lower() == "as:hashtag":
|
||||
elif tag["type"].lower() == "hashtag":
|
||||
post.hashtags.append(tag["name"].lower().lstrip("#"))
|
||||
elif tag["type"].lower() == "http://joinmastodon.org/ns#emoji":
|
||||
emoji = Emoji.by_ap_tag(post.author.domain, tag, create=True)
|
||||
|
|
|
@ -415,6 +415,7 @@ def canonicalise(json_data: dict, include_security: bool = False) -> dict:
|
|||
"votersCount": "toot:votersCount",
|
||||
"Hashtag": "as:Hashtag",
|
||||
"Public": "as:Public",
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
},
|
||||
]
|
||||
if include_security:
|
||||
|
|
|
@ -96,9 +96,14 @@ urlpatterns = [
|
|||
),
|
||||
path(
|
||||
"admin/users/",
|
||||
admin.Users.as_view(),
|
||||
admin.UsersRoot.as_view(),
|
||||
name="admin_users",
|
||||
),
|
||||
path(
|
||||
"admin/users/<id>/",
|
||||
admin.UserEdit.as_view(),
|
||||
name="admin_user_edit",
|
||||
),
|
||||
path(
|
||||
"admin/identities/",
|
||||
admin.Identities.as_view(),
|
||||
|
|
36
templates/admin/user_edit.html
Normal file
36
templates/admin/user_edit.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "settings/base.html" %}
|
||||
|
||||
{% block subtitle %}{{ user.email }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ editing_user.email }}</h1>
|
||||
<form action="." method="POST">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>Permissions</legend>
|
||||
{% include "forms/_field.html" with field=form.status %}
|
||||
{% if same_user %}
|
||||
<ul class="errorlist">
|
||||
<li>You cannot edit your own permission status!</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Identities</legend>
|
||||
{% for identity in editing_user.identities.all %}
|
||||
{% include "activities/_identity.html" %}
|
||||
{% empty %}
|
||||
<p>This user has no identities yet.</p>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Dates</legend>
|
||||
<p>Last seen: <time title="{{ editing_user.last_seen }} UTC">{{ editing_user.last_seen | timesince }} ago</time></p>
|
||||
<p>Created: <time title="{{ editing_user.created }} UTC">{{ editing_user.created | timesince }} ago</time></p>
|
||||
</fieldset>
|
||||
<div class="buttons">
|
||||
<a href="{{ editing_user.urls.admin }}" class="button secondary left">Back</a>
|
||||
<button>Save</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -3,7 +3,40 @@
|
|||
{% block subtitle %}Users{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
Please use the <a href="/djadmin/users/user/">Django Admin</a> for now.
|
||||
</p>
|
||||
<form action="." class="search">
|
||||
<input type="search" name="query" value="{{ query }}" placeholder="Search by email">
|
||||
<button><i class="fa-solid fa-search"></i></button>
|
||||
</form>
|
||||
<section class="icon-menu">
|
||||
{% for user in page_obj %}
|
||||
<a class="option" href="{{ user.urls.admin_edit }}">
|
||||
<i class="fa-solid fa-user"></i>
|
||||
<span class="handle">
|
||||
{{ user.email }}
|
||||
<small>
|
||||
{{ user.num_identities }} identit{{ user.num_identities|pluralize:"y,ies" }}
|
||||
</small>
|
||||
</span>
|
||||
{% if user.banned %}
|
||||
<span class="pill bad">Banned</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% empty %}
|
||||
<p class="option empty">
|
||||
{% if query %}
|
||||
No users match your query.
|
||||
{% else %}
|
||||
There are no users yet.
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endfor %}
|
||||
<div class="load-more">
|
||||
{% if page_obj.has_previous %}
|
||||
<a class="button" href=".?page={{ page_obj.previous_page_number }}">Previous Page</a>
|
||||
{% endif %}
|
||||
{% if page_obj.has_next %}
|
||||
<a class="button" href=".?page={{ page_obj.next_page_number }}">Next Page</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
|
|
@ -155,7 +155,7 @@ def test_fetch_actor(httpx_mock, config_system):
|
|||
"mediaType": "image/jpeg",
|
||||
"url": "https://example.com/image.jpg",
|
||||
},
|
||||
"as:manuallyApprovesFollowers": False,
|
||||
"manuallyApprovesFollowers": False,
|
||||
"name": "Test User",
|
||||
"preferredUsername": "test",
|
||||
"published": "2022-11-02T00:00:00Z",
|
||||
|
|
|
@ -89,7 +89,13 @@ class PasswordResetAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(InboxMessage)
|
||||
class InboxMessageAdmin(admin.ModelAdmin):
|
||||
list_display = ["id", "state", "state_changed", "message_type", "message_actor"]
|
||||
list_display = [
|
||||
"id",
|
||||
"state",
|
||||
"state_changed",
|
||||
"message_type_full",
|
||||
"message_actor",
|
||||
]
|
||||
list_filter = ("state",)
|
||||
search_fields = ["message"]
|
||||
actions = ["reset_state"]
|
||||
|
|
|
@ -438,7 +438,7 @@ class Identity(StatorModel):
|
|||
self.username = self.username["@value"]
|
||||
if self.username:
|
||||
self.username = self.username.lower()
|
||||
self.manually_approves_followers = document.get("as:manuallyApprovesFollowers")
|
||||
self.manually_approves_followers = document.get("manuallyApprovesFollowers")
|
||||
self.public_key = document.get("publicKey", {}).get("publicKeyPem")
|
||||
self.public_key_id = document.get("publicKey", {}).get("id")
|
||||
self.icon_uri = document.get("icon", {}).get("url")
|
||||
|
|
|
@ -115,6 +115,13 @@ class InboxMessage(StatorModel):
|
|||
def message_object_type(self):
|
||||
return self.message["object"]["type"].lower()
|
||||
|
||||
@property
|
||||
def message_type_full(self):
|
||||
if isinstance(self.message.get("object"), dict):
|
||||
return f"{self.message_type}.{self.message_object_type}"
|
||||
else:
|
||||
return f"{self.message_type}"
|
||||
|
||||
@property
|
||||
def message_actor(self):
|
||||
return self.message.get("actor")
|
||||
|
|
|
@ -48,7 +48,7 @@ class SystemActor:
|
|||
},
|
||||
"preferredUsername": self.username,
|
||||
"url": self.profile_uri,
|
||||
"as:manuallyApprovesFollowers": True,
|
||||
"manuallyApprovesFollowers": True,
|
||||
"publicKey": {
|
||||
"id": self.public_key_id,
|
||||
"owner": self.actor_uri,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import urlman
|
||||
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
|
||||
from django.db import models
|
||||
|
||||
|
@ -44,6 +45,10 @@ class User(AbstractBaseUser):
|
|||
|
||||
objects = UserManager()
|
||||
|
||||
class urls(urlman.Urls):
|
||||
admin = "/admin/users/"
|
||||
admin_edit = "{admin}{self.pk}/"
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
return not (self.deleted or self.banned)
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.utils.decorators import method_decorator
|
|||
from django.views.generic import FormView, RedirectView, TemplateView
|
||||
|
||||
from users.decorators import admin_required
|
||||
from users.models import Identity, User
|
||||
from users.models import Identity
|
||||
from users.views.admin.domains import ( # noqa
|
||||
DomainCreate,
|
||||
DomainDelete,
|
||||
|
@ -23,6 +23,7 @@ from users.views.admin.settings import ( # noqa
|
|||
TuningSettings,
|
||||
)
|
||||
from users.views.admin.stator import Stator # noqa
|
||||
from users.views.admin.users import UserEdit, UsersRoot # noqa
|
||||
|
||||
|
||||
@method_decorator(admin_required, name="dispatch")
|
||||
|
@ -30,18 +31,6 @@ class AdminRoot(RedirectView):
|
|||
pattern_name = "admin_basic"
|
||||
|
||||
|
||||
@method_decorator(admin_required, name="dispatch")
|
||||
class Users(TemplateView):
|
||||
|
||||
template_name = "admin/users.html"
|
||||
|
||||
def get_context_data(self):
|
||||
return {
|
||||
"users": User.objects.order_by("email"),
|
||||
"section": "users",
|
||||
}
|
||||
|
||||
|
||||
@method_decorator(admin_required, name="dispatch")
|
||||
class Identities(TemplateView):
|
||||
|
||||
|
|
84
users/views/admin/users.py
Normal file
84
users/views/admin/users.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
from django import forms
|
||||
from django.db import models
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import FormView, ListView
|
||||
|
||||
from users.decorators import admin_required
|
||||
from users.models import User
|
||||
|
||||
|
||||
@method_decorator(admin_required, name="dispatch")
|
||||
class UsersRoot(ListView):
|
||||
|
||||
template_name = "admin/users.html"
|
||||
paginate_by = 50
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.query = request.GET.get("query")
|
||||
self.extra_context = {
|
||||
"section": "users",
|
||||
"query": self.query or "",
|
||||
}
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
users = User.objects.annotate(
|
||||
num_identities=models.Count("identities")
|
||||
).order_by("created")
|
||||
if self.query:
|
||||
users = users.filter(email__icontains=self.query)
|
||||
return users
|
||||
|
||||
|
||||
@method_decorator(admin_required, name="dispatch")
|
||||
class UserEdit(FormView):
|
||||
|
||||
template_name = "admin/user_edit.html"
|
||||
extra_context = {
|
||||
"section": "users",
|
||||
}
|
||||
|
||||
class form_class(forms.Form):
|
||||
status = forms.ChoiceField(
|
||||
choices=[
|
||||
("normal", "Normal User"),
|
||||
("moderator", "Moderator"),
|
||||
("admin", "Admin"),
|
||||
("banned", "Banned"),
|
||||
]
|
||||
)
|
||||
|
||||
def dispatch(self, request, id, *args, **kwargs):
|
||||
self.user = get_object_or_404(User, id=id)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
status = "normal"
|
||||
if self.user.moderator:
|
||||
status = "moderator"
|
||||
if self.user.admin:
|
||||
status = "admin"
|
||||
if self.user.banned:
|
||||
status = "banned"
|
||||
return {
|
||||
"email": self.user.email,
|
||||
"status": status,
|
||||
}
|
||||
|
||||
def form_valid(self, form):
|
||||
# Don't let them change themselves
|
||||
if self.user == self.request.user:
|
||||
return redirect(".")
|
||||
status = form.cleaned_data["status"]
|
||||
self.user.banned = status == "banned"
|
||||
self.user.moderator = status == "moderator"
|
||||
self.user.admin = status == "admin"
|
||||
self.user.save()
|
||||
return redirect(self.user.urls.admin)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["editing_user"] = self.user
|
||||
context["same_user"] = self.user == self.request.user
|
||||
return context
|
Loading…
Reference in a new issue