mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-12-04 23:36:32 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
7284a4efad
18 changed files with 243 additions and 30 deletions
|
@ -362,6 +362,13 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin):
|
||||||
self.collection_queryset, **kwargs
|
self.collection_queryset, **kwargs
|
||||||
).serialize()
|
).serialize()
|
||||||
|
|
||||||
|
def delete(self, *args, broadcast=True, **kwargs):
|
||||||
|
"""Delete the object"""
|
||||||
|
activity = self.to_delete_activity(self.user)
|
||||||
|
super().delete(*args, **kwargs)
|
||||||
|
if self.user.local and broadcast:
|
||||||
|
self.broadcast(activity, self.user)
|
||||||
|
|
||||||
|
|
||||||
class CollectionItemMixin(ActivitypubMixin):
|
class CollectionItemMixin(ActivitypubMixin):
|
||||||
"""for items that are part of an (Ordered)Collection"""
|
"""for items that are part of an (Ordered)Collection"""
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'lists/list_layout.html' %}
|
{% extends 'lists/layout.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block panel %}
|
{% block panel %}
|
||||||
|
|
||||||
|
|
21
bookwyrm/templates/lists/delete_list_modal.html
Normal file
21
bookwyrm/templates/lists/delete_list_modal.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% extends 'components/modal.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-title %}{% trans "Delete this list?" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
{% trans "This action cannot be un-done" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<form name="delete-list-{{ list.id }}" action="{% url 'delete-list' list.id %}" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="id" value="{{ list.id }}">
|
||||||
|
<button class="button is-danger" type="submit">
|
||||||
|
{% trans "Delete" %}
|
||||||
|
</button>
|
||||||
|
{% trans "Cancel" as button_text %}
|
||||||
|
{% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="delete_list" controls_uid=list.id %}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -9,4 +9,5 @@
|
||||||
<form name="edit-list" method="post" action="{% url 'list' list.id %}">
|
<form name="edit-list" method="post" action="{% url 'list' list.id %}">
|
||||||
{% include 'lists/form.html' %}
|
{% include 'lists/form.html' %}
|
||||||
</form>
|
</form>
|
||||||
|
{% include "lists/delete_list_modal.html" with controls_text="delete_list" controls_uid=list.id %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<input type="hidden" name="user" value="{{ request.user.id }}">
|
<input type="hidden" name="user" value="{{ request.user.id }}">
|
||||||
|
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column is-two-thirds">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="id_name">{% trans "Name:" %}</label>
|
<label class="label" for="id_name">{% trans "Name:" %}</label>
|
||||||
{{ list_form.name }}
|
{{ list_form.name }}
|
||||||
|
@ -34,6 +34,8 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="columns is-mobile">
|
||||||
|
<div class="column">
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
{% include 'snippets/privacy_select.html' with current=list.privacy %}
|
{% include 'snippets/privacy_select.html' with current=list.privacy %}
|
||||||
|
@ -42,4 +44,9 @@
|
||||||
<button type="submit" class="button is-primary">{% trans "Save" %}</button>
|
<button type="submit" class="button is-primary">{% trans "Save" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column is-narrow">
|
||||||
|
{% trans "Delete list" as button_text %}
|
||||||
|
{% include 'snippets/toggle/toggle_button.html' with class="is-danger" text=button_text icon_with_text="x" controls_text="delete_list" controls_uid=list.id focus="modal_title_delete_list" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'lists/list_layout.html' %}
|
{% extends 'lists/layout.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bookwyrm_tags %}
|
{% load bookwyrm_tags %}
|
||||||
{% load markdown %}
|
{% load markdown %}
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{{ user.username }}{% endblock %}
|
{% block title %}{{ user.username }}{% endblock %}
|
||||||
{% block header %}{{ user.username }}{% endblock %}
|
{% block header %}
|
||||||
|
{{ user.username }}
|
||||||
|
<p class="help has-text-weight-normal">
|
||||||
|
<a href="{% url 'settings-users' %}">{% trans "Back to users" %}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block panel %}
|
{% block panel %}
|
||||||
<div class="block">
|
|
||||||
<a href="{% url 'settings-users' %}">{% trans "Back to users" %}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include 'user_admin/user_info.html' with user=user %}
|
{% include 'user_admin/user_info.html' with user=user %}
|
||||||
|
|
||||||
{% include 'user_admin/user_moderation_actions.html' with user=user %}
|
{% include 'user_admin/user_moderation_actions.html' with user=user %}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends 'snippets/filters_panel/filters_panel.html' %}
|
{% extends 'snippets/filters_panel/filters_panel.html' %}
|
||||||
|
|
||||||
{% block filter_fields %}
|
{% block filter_fields %}
|
||||||
{% include 'user_admin/server_filter.html' %}
|
|
||||||
{% include 'user_admin/username_filter.html' %}
|
{% include 'user_admin/username_filter.html' %}
|
||||||
{% include 'directory/community_filter.html' %}
|
{% include 'directory/community_filter.html' %}
|
||||||
|
{% include 'user_admin/server_filter.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load markdown %}
|
{% load markdown %}
|
||||||
|
{% load humanize %}
|
||||||
|
|
||||||
<div class="block columns">
|
<div class="block columns">
|
||||||
<div class="column is-flex is-flex-direction-column">
|
<div class="column is-flex is-flex-direction-column">
|
||||||
<h4 class="title is-4">{% trans "User details" %}</h4>
|
<h4 class="title is-4">{% trans "Profile" %}</h4>
|
||||||
<div class="box is-flex-grow-1">
|
<div class="box is-flex-grow-1">
|
||||||
{% include 'user/user_preview.html' with user=user %}
|
{% include 'user/user_preview.html' with user=user %}
|
||||||
{% if user.summary %}
|
{% if user.summary %}
|
||||||
|
@ -14,6 +16,95 @@
|
||||||
<p class="mt-2"><a href="{{ user.local_path }}">{% trans "View user profile" %}</a></p>
|
<p class="mt-2"><a href="{{ user.local_path }}">{% trans "View user profile" %}</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="column is-flex is-flex-direction-column is-4">
|
||||||
|
<h4 class="title is-4">{% trans "Status" %}</h4>
|
||||||
|
<div class="box is-flex-grow-1 has-text-weight-bold">
|
||||||
|
{% if user.is_active %}
|
||||||
|
<p class="notification is-success">
|
||||||
|
{% trans "Active" %}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="notification is-warning">
|
||||||
|
{% trans "Inactive" %}
|
||||||
|
{% if user.deactivation_reason %}
|
||||||
|
({{ user.deactivation_reason }})
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<p class="notification">
|
||||||
|
{% if user.local %}
|
||||||
|
{% trans "Local" %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Remote" %}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="block columns">
|
||||||
|
<div class="column is-flex is-flex-direction-column">
|
||||||
|
<h4 class="title is-4">{% trans "User details" %}</h4>
|
||||||
|
<div class="box content is-flex-grow-1">
|
||||||
|
<dl>
|
||||||
|
{% if user.local %}
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Email:" %}</dt>
|
||||||
|
<dd>{{ user.email }}</dd>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% with report_count=user.report_set.count %}
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Reports:" %}</dt>
|
||||||
|
<dd>
|
||||||
|
{{ report_count|intcomma }}
|
||||||
|
{% if report_count > 0 %}
|
||||||
|
<a href="{% url 'settings-reports' %}?username={{ user.username }}">
|
||||||
|
{% trans "(View reports)" %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Blocked by count:" %}</dt>
|
||||||
|
<dd>{{ user.blocked_by.count }}</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Last active date:" %}</dt>
|
||||||
|
<dd>{{ user.last_active_date }}</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Manually approved followers:" %}</dt>
|
||||||
|
<dd>{{ user.manually_approves_followers }}</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Discoverable:" %}</dt>
|
||||||
|
<dd>{{ user.discoverable }}</dd>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if not user.is_active %}
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Deactivation reason:" %}</dt>
|
||||||
|
<dd>{{ user.deactivation_reason }}</dd>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not user.is_active and user.deactivation_reason == "pending" %}
|
||||||
|
<div class="is-flex">
|
||||||
|
<dt>{% trans "Confirmation code:" %}</dt>
|
||||||
|
<dd>{{ user.confirmation_code }}</dd>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if not user.local %}
|
{% if not user.local %}
|
||||||
{% with server=user.federated_server %}
|
{% with server=user.federated_server %}
|
||||||
<div class="column is-half is-flex is-flex-direction-column">
|
<div class="column is-half is-flex is-flex-direction-column">
|
||||||
|
|
|
@ -40,14 +40,6 @@ class InboxActivities(TestCase):
|
||||||
remote_id="https://example.com/status/1",
|
remote_id="https://example.com/status/1",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.create_json = {
|
|
||||||
"id": "hi",
|
|
||||||
"type": "Create",
|
|
||||||
"actor": "hi",
|
|
||||||
"to": ["https://www.w3.org/ns/activitystreams#public"],
|
|
||||||
"cc": ["https://example.com/user/mouse/followers"],
|
|
||||||
"object": {},
|
|
||||||
}
|
|
||||||
models.SiteSettings.objects.create()
|
models.SiteSettings.objects.create()
|
||||||
|
|
||||||
def test_delete_status(self):
|
def test_delete_status(self):
|
||||||
|
@ -137,3 +129,30 @@ class InboxActivities(TestCase):
|
||||||
# nothing happens.
|
# nothing happens.
|
||||||
views.inbox.activity_task(activity)
|
views.inbox.activity_task(activity)
|
||||||
self.assertEqual(models.User.objects.filter(is_active=True).count(), 2)
|
self.assertEqual(models.User.objects.filter(is_active=True).count(), 2)
|
||||||
|
|
||||||
|
def test_delete_list(self):
|
||||||
|
"""delete a list"""
|
||||||
|
book_list = models.List.objects.create(
|
||||||
|
name="test list",
|
||||||
|
user=self.remote_user,
|
||||||
|
remote_id="https://example.com/list/1",
|
||||||
|
)
|
||||||
|
activity = {
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id": "https://example.com/users/test-user#delete",
|
||||||
|
"type": "Delete",
|
||||||
|
"actor": "https://example.com/users/test-user",
|
||||||
|
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"object": {
|
||||||
|
"id": book_list.remote_id,
|
||||||
|
"owner": self.remote_user.remote_id,
|
||||||
|
"type": "BookList",
|
||||||
|
"totalItems": 0,
|
||||||
|
"first": "",
|
||||||
|
"name": "test list",
|
||||||
|
"to": [],
|
||||||
|
"cc": [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views.inbox.activity_task(activity)
|
||||||
|
self.assertFalse(models.List.objects.exists())
|
||||||
|
|
|
@ -3,6 +3,7 @@ import json
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
|
@ -66,6 +67,44 @@ class ListActionViews(TestCase):
|
||||||
self.anonymous_user.is_authenticated = False
|
self.anonymous_user.is_authenticated = False
|
||||||
models.SiteSettings.objects.create()
|
models.SiteSettings.objects.create()
|
||||||
|
|
||||||
|
def test_delete_list(self):
|
||||||
|
"""delete an entire list"""
|
||||||
|
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||||
|
models.ListItem.objects.create(
|
||||||
|
book_list=self.list,
|
||||||
|
user=self.local_user,
|
||||||
|
book=self.book,
|
||||||
|
approved=True,
|
||||||
|
order=1,
|
||||||
|
)
|
||||||
|
models.ListItem.objects.create(
|
||||||
|
book_list=self.list,
|
||||||
|
user=self.local_user,
|
||||||
|
book=self.book_two,
|
||||||
|
approved=False,
|
||||||
|
order=2,
|
||||||
|
)
|
||||||
|
request = self.factory.post("")
|
||||||
|
request.user = self.local_user
|
||||||
|
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
|
||||||
|
views.delete_list(request, self.list.id)
|
||||||
|
activity = json.loads(mock.call_args[0][1])
|
||||||
|
self.assertEqual(activity["type"], "Delete")
|
||||||
|
self.assertEqual(activity["actor"], self.local_user.remote_id)
|
||||||
|
self.assertEqual(activity["object"]["id"], self.list.remote_id)
|
||||||
|
self.assertEqual(activity["object"]["type"], "BookList")
|
||||||
|
|
||||||
|
self.assertEqual(mock.call_count, 1)
|
||||||
|
self.assertFalse(models.List.objects.exists())
|
||||||
|
self.assertFalse(models.ListItem.objects.exists())
|
||||||
|
|
||||||
|
def test_delete_list_permission_denied(self):
|
||||||
|
"""delete an entire list"""
|
||||||
|
request = self.factory.post("")
|
||||||
|
request.user = self.rat
|
||||||
|
with self.assertRaises(PermissionDenied):
|
||||||
|
views.delete_list(request, self.list.id)
|
||||||
|
|
||||||
def test_curate_approve(self):
|
def test_curate_approve(self):
|
||||||
"""approve a pending item"""
|
"""approve a pending item"""
|
||||||
view = views.Curate.as_view()
|
view = views.Curate.as_view()
|
||||||
|
|
|
@ -220,6 +220,7 @@ urlpatterns = [
|
||||||
re_path(r"^list/?$", views.Lists.as_view(), name="lists"),
|
re_path(r"^list/?$", views.Lists.as_view(), name="lists"),
|
||||||
re_path(r"^list/saved/?$", views.SavedLists.as_view(), name="saved-lists"),
|
re_path(r"^list/saved/?$", views.SavedLists.as_view(), name="saved-lists"),
|
||||||
re_path(r"^list/(?P<list_id>\d+)(.json)?/?$", views.List.as_view(), name="list"),
|
re_path(r"^list/(?P<list_id>\d+)(.json)?/?$", views.List.as_view(), name="list"),
|
||||||
|
re_path(r"^list/delete/(?P<list_id>\d+)/?$", views.delete_list, name="delete-list"),
|
||||||
re_path(r"^list/add-book/?$", views.list.add_book, name="list-add-book"),
|
re_path(r"^list/add-book/?$", views.list.add_book, name="list-add-book"),
|
||||||
re_path(
|
re_path(
|
||||||
r"^list/(?P<list_id>\d+)/remove/?$",
|
r"^list/(?P<list_id>\d+)/remove/?$",
|
||||||
|
|
|
@ -27,6 +27,7 @@ from .isbn import Isbn
|
||||||
from .landing import About, Home, Landing
|
from .landing import About, Home, Landing
|
||||||
from .list import Lists, SavedLists, List, Curate, UserLists
|
from .list import Lists, SavedLists, List, Curate, UserLists
|
||||||
from .list import save_list, unsave_list
|
from .list import save_list, unsave_list
|
||||||
|
from .list import delete_list
|
||||||
from .notifications import Notifications
|
from .notifications import Notifications
|
||||||
from .outbox import Outbox
|
from .outbox import Outbox
|
||||||
from .reading import edit_readthrough, create_readthrough
|
from .reading import edit_readthrough, create_readthrough
|
||||||
|
|
|
@ -16,6 +16,7 @@ class Discover(View):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""tiled book activity page"""
|
"""tiled book activity page"""
|
||||||
|
# all activities in the "federated" feed associated with a book
|
||||||
activities = (
|
activities = (
|
||||||
activitystreams.streams["local"]
|
activitystreams.streams["local"]
|
||||||
.get_activity_stream(request.user)
|
.get_activity_stream(request.user)
|
||||||
|
@ -29,13 +30,19 @@ class Discover(View):
|
||||||
|
|
||||||
large_activities = Paginator(
|
large_activities = Paginator(
|
||||||
activities.filter(mention_books__isnull=True)
|
activities.filter(mention_books__isnull=True)
|
||||||
.exclude(content=None, quotation__quote=None)
|
# exclude statuses with no user-provided content for large panels
|
||||||
.exclude(content=""),
|
.exclude(
|
||||||
|
Q(Q(content="") | Q(content__isnull=True)) & Q(quotation__isnull=True),
|
||||||
|
),
|
||||||
6,
|
6,
|
||||||
)
|
)
|
||||||
small_activities = Paginator(
|
small_activities = Paginator(
|
||||||
activities.filter(
|
activities.filter(
|
||||||
Q(mention_books__isnull=False) | Q(content=None) | Q(content="")
|
Q(mention_books__isnull=False)
|
||||||
|
| Q(
|
||||||
|
Q(Q(content="") | Q(content__isnull=True))
|
||||||
|
& Q(quotation__isnull=True),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
4,
|
4,
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from typing import Optional
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.db import IntegrityError, transaction
|
from django.db import IntegrityError, transaction
|
||||||
from django.db.models import Avg, Count, DecimalField, Q, Max
|
from django.db.models import Avg, Count, DecimalField, Q, Max
|
||||||
|
@ -260,6 +261,20 @@ def unsave_list(request, list_id):
|
||||||
return redirect("list", list_id)
|
return redirect("list", list_id)
|
||||||
|
|
||||||
|
|
||||||
|
@require_POST
|
||||||
|
@login_required
|
||||||
|
def delete_list(request, list_id):
|
||||||
|
"""delete a list"""
|
||||||
|
book_list = get_object_or_404(models.List, id=list_id)
|
||||||
|
|
||||||
|
# only the owner or a moderator can delete a list
|
||||||
|
if book_list.user != request.user and not request.user.has_perm("moderate_post"):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
book_list.delete()
|
||||||
|
return redirect("lists")
|
||||||
|
|
||||||
|
|
||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def add_book(request):
|
def add_book(request):
|
||||||
|
|
|
@ -31,8 +31,8 @@ class UserAdminList(View):
|
||||||
if username:
|
if username:
|
||||||
filters["username__icontains"] = username
|
filters["username__icontains"] = username
|
||||||
scope = request.GET.get("scope")
|
scope = request.GET.get("scope")
|
||||||
if scope:
|
if scope and scope == "local":
|
||||||
filters["local"] = scope == "local"
|
filters["local"] = True
|
||||||
|
|
||||||
users = models.User.objects.filter(**filters)
|
users = models.User.objects.filter(**filters)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ server {
|
||||||
# listen 443 ssl http2;
|
# listen 443 ssl http2;
|
||||||
#
|
#
|
||||||
# server_name your-domain.com;
|
# server_name your-domain.com;
|
||||||
|
#
|
||||||
|
# client_max_body_size 3M;
|
||||||
|
#
|
||||||
# if ($host != "you-domain.com") {
|
# if ($host != "you-domain.com") {
|
||||||
# return 301 $scheme://your-domain.com$request_uri;
|
# return 301 $scheme://your-domain.com$request_uri;
|
||||||
# }
|
# }
|
||||||
|
|
Loading…
Reference in a new issue