Merge branch 'main' of https://gitea.corbz.dev/corbz/PYRSS-Website
This commit is contained in:
commit
32ff185640
@ -1,6 +1,12 @@
|
|||||||
from rest_framework import serializers
|
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from rest_framework import serializers, fields
|
||||||
from rest_framework.metadata import SimpleMetadata
|
from rest_framework.metadata import SimpleMetadata
|
||||||
from rest_framework.request import clone_request
|
from rest_framework.request import clone_request
|
||||||
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ExpandedMetadata(SimpleMetadata):
|
class ExpandedMetadata(SimpleMetadata):
|
||||||
@ -11,6 +17,9 @@ class ExpandedMetadata(SimpleMetadata):
|
|||||||
if hasattr(view, "ordering_fields"):
|
if hasattr(view, "ordering_fields"):
|
||||||
metadata["sort"] = view.ordering_fields
|
metadata["sort"] = view.ordering_fields
|
||||||
|
|
||||||
|
if hasattr(view, "filterset_fields"):
|
||||||
|
metadata["filter"] = view.filterset_fields
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
def determine_actions(self, request, view):
|
def determine_actions(self, request, view):
|
||||||
@ -39,3 +48,13 @@ class ExpandedMetadata(SimpleMetadata):
|
|||||||
view.request = request
|
view.request = request
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
def get_field_info(self, field):
|
||||||
|
field_info = super().get_field_info(field)
|
||||||
|
if hasattr(field, 'default') and field.default is not fields.empty:
|
||||||
|
field_info['default'] = field.default
|
||||||
|
|
||||||
|
if hasattr(field, 'initial') and field.initial is not fields.empty:
|
||||||
|
field_info['initial'] = field.initial
|
||||||
|
|
||||||
|
return field_info
|
||||||
|
@ -143,6 +143,7 @@ class SubscriptionSerializer_GET(DynamicModelSerializer):
|
|||||||
|
|
||||||
article_title_mutators = ArticleMutatorSerializer(many=True)
|
article_title_mutators = ArticleMutatorSerializer(many=True)
|
||||||
article_desc_mutators = ArticleMutatorSerializer(many=True)
|
article_desc_mutators = ArticleMutatorSerializer(many=True)
|
||||||
|
active = serializers.BooleanField(initial=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Subscription
|
model = Subscription
|
||||||
|
@ -152,7 +152,12 @@ async function deleteSelectedContent() {
|
|||||||
var rows = contentTable.rows(".selected").data();
|
var rows = contentTable.rows(".selected").data();
|
||||||
$.each(rows, async function() {
|
$.each(rows, async function() {
|
||||||
await deleteTrackedContent(this.id);
|
await deleteTrackedContent(this.id);
|
||||||
showToast("danger", "Deleted Tracked Content", "It can now appear be sent again. Content ID: " + this.id);
|
showToast(
|
||||||
|
"success",
|
||||||
|
"Deletion Successful",
|
||||||
|
`This content may appear again under the <b>${this.subscription.name}</b> Subscription:<br><br>${this.guid}`,
|
||||||
|
10000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
@ -246,7 +246,12 @@ async function deleteSelectedFilters() {
|
|||||||
var rows = filtersTable.rows(".selected").data();
|
var rows = filtersTable.rows(".selected").data();
|
||||||
$.each(rows, async function() {
|
$.each(rows, async function() {
|
||||||
await deleteFilter(this.id);
|
await deleteFilter(this.id);
|
||||||
showToast("danger", "Deleted Filter", "Filter ID: " + this.id)
|
showToast(
|
||||||
|
"success",
|
||||||
|
"Deletion Successful",
|
||||||
|
`Content Filter <b>${this.name}</b> has been erased.`,
|
||||||
|
10000
|
||||||
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
@ -258,8 +263,15 @@ async function deleteSelectedFilters() {
|
|||||||
|
|
||||||
$("#deleteEditFilter").on("click", async function() {
|
$("#deleteEditFilter").on("click", async function() {
|
||||||
const filterId = $("#filterId").val();
|
const filterId = $("#filterId").val();
|
||||||
|
const row = filtersTable.row(function(index, row) {row.id == id}).data();
|
||||||
|
alert(filterId + JSON.stringify(row, null, 4))
|
||||||
await deleteFilter(filterId);
|
await deleteFilter(filterId);
|
||||||
await loadFilters(getCurrentlyActiveServer().guild_id);
|
await loadFilters(getCurrentlyActiveServer().guild_id);
|
||||||
$("#filterFormModal").modal("hide");
|
$("#filterFormModal").modal("hide");
|
||||||
showToast("danger", "Deleted Filter", "Filter ID: " + filterId);
|
showToast(
|
||||||
|
"success",
|
||||||
|
"Deletion Successful",
|
||||||
|
`Content Filter <b>${row.name}</b> has been erased.`,
|
||||||
|
10000
|
||||||
|
);
|
||||||
});
|
});
|
@ -11,6 +11,8 @@ async function initTable(containingSelector, tableId, loadDataFunc, newRowFunc,
|
|||||||
createTableControls(containingSelector, pageSizeId);
|
createTableControls(containingSelector, pageSizeId);
|
||||||
|
|
||||||
await bindSearchBar(searchId, loadDataFunc);
|
await bindSearchBar(searchId, loadDataFunc);
|
||||||
|
// await bindSortDropdown(sortDropdownId, loadDataFunc);
|
||||||
|
await bindFilterDropdown(filterDropdownId, loadDataFunc);
|
||||||
await bindTablePagination(`${containingSelector} .table-pagination`, loadDataFunc);
|
await bindTablePagination(`${containingSelector} .table-pagination`, loadDataFunc);
|
||||||
await bindTablePaginationResizer(`${containingSelector} .table-page-sizer`, loadDataFunc);
|
await bindTablePaginationResizer(`${containingSelector} .table-page-sizer`, loadDataFunc);
|
||||||
}
|
}
|
||||||
@ -50,8 +52,8 @@ function createSearchRow(containingSelector, searchId, sortDropdownId, filterDro
|
|||||||
if (options.sort) {
|
if (options.sort) {
|
||||||
$(`${containingSelector} .table-search-row .table-search-buttons`).append(`
|
$(`${containingSelector} .table-search-row .table-search-buttons`).append(`
|
||||||
<div class="d-inline-block ms-3">
|
<div class="d-inline-block ms-3">
|
||||||
<div id=${sortDropdownId} class="dropdown table-sort-dropdown">
|
<div id="${sortDropdownId}" class="dropdown table-sort-dropdown">
|
||||||
<button type="button" class="btn btn-secondary rounded-1" data-bs-toggle="dropdown">
|
<button type="button" class="btn btn-secondary rounded-1" data-bs-toggle="dropdown" data-bs-auto-close="outside">
|
||||||
<i class="bi bi-sort-alpha-up"></i>
|
<i class="bi bi-sort-alpha-up"></i>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
@ -63,11 +65,11 @@ function createSearchRow(containingSelector, searchId, sortDropdownId, filterDro
|
|||||||
populateSortDropdown(sortDropdownId, options.sort);
|
populateSortDropdown(sortDropdownId, options.sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.actions.GET) {
|
if (options.filter && options.actions.GET) {
|
||||||
$(`${containingSelector} .table-search-row .table-search-buttons`).append(`
|
$(`${containingSelector} .table-search-row .table-search-buttons`).append(`
|
||||||
<div class="d-inline-block ms-3">
|
<div class="d-inline-block ms-3">
|
||||||
<div id=${filterDropdownId} class="dropdown table-filter-dropdown">
|
<div id="${filterDropdownId}" class="dropdown table-filter-dropdown">
|
||||||
<button type="button" class="btn btn-secondary rounded-1" data-bs-toggle="dropdown">
|
<button type="button" class="btn btn-secondary rounded-1" data-bs-toggle="dropdown" data-bs-auto-close="outside">
|
||||||
<i class="bi bi-funnel"></i>
|
<i class="bi bi-funnel"></i>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
@ -76,7 +78,7 @@ function createSearchRow(containingSelector, searchId, sortDropdownId, filterDro
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
populateFilterDropdown();
|
populateFilterDropdown(filterDropdownId, options.actions.GET, options.filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteSelectedFunc) {
|
if (deleteSelectedFunc) {
|
||||||
@ -93,7 +95,7 @@ function createSearchRow(containingSelector, searchId, sortDropdownId, filterDro
|
|||||||
|
|
||||||
function populateSortDropdown(sortDropdownId, sortOptions) {
|
function populateSortDropdown(sortDropdownId, sortOptions) {
|
||||||
sortOptions.forEach(sortKey => {
|
sortOptions.forEach(sortKey => {
|
||||||
let label = sortKey.replace(/_/g, " ")
|
let label = sortKey.replace(/_/g, " ");
|
||||||
$(`#${sortDropdownId} .dropdown-menu`).append(`
|
$(`#${sortDropdownId} .dropdown-menu`).append(`
|
||||||
<li>
|
<li>
|
||||||
<button type="button" class="dropdown-item text-capitalize d-flex justify-content-between" data-sortkey="${sortKey}">
|
<button type="button" class="dropdown-item text-capitalize d-flex justify-content-between" data-sortkey="${sortKey}">
|
||||||
@ -109,19 +111,101 @@ function populateSortDropdown(sortDropdownId, sortOptions) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateFilterDropdown() { }
|
function populateFilterDropdown(filterDropdownId, options, filterKeys) {
|
||||||
|
for (key in options) {
|
||||||
|
if (!filterKeys.includes(key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let label = options[key].label; // key.replace(/_/g, " ");
|
||||||
|
id = key + "Filter";
|
||||||
|
$elem = null;
|
||||||
|
|
||||||
|
switch (options[key].type) {
|
||||||
|
case ("boolean"):
|
||||||
|
$elem = $(`
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" name="${id}" id="${id}" class="btn-check" autocomplete="off" data-key="${key}">
|
||||||
|
<label for="${id}" class="dropdown-item d-flex justify-content-between" role="button">
|
||||||
|
<span>${label}</span>
|
||||||
|
<i class="bi bi-x"></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
bindFilterBoolean($elem);
|
||||||
|
$elem.find('input[type="checkbox"]').prop("checked", options[key].default ? true : false).trigger("change");
|
||||||
|
updateCheckboxState($elem);
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(`#${filterDropdownId} .dropdown-menu`).append($("<li>").append($elem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindFilterBoolean($elem) {
|
||||||
|
$elem.find('label').on("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let $input = $elem.find('input[type="checkbox"]');
|
||||||
|
let state = $input.data("state");
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case true:
|
||||||
|
state = false;
|
||||||
|
break;
|
||||||
|
case false:
|
||||||
|
state = null;
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
default:
|
||||||
|
state = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.data("state", state);
|
||||||
|
updateCheckboxState($elem);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCheckboxState($elem) {
|
||||||
|
let state = $elem.find('input[type="checkbox"]').data("state");
|
||||||
|
let $icon = $elem.find(".bi");
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case true:
|
||||||
|
$elem.find('input[type="checkbox"]').prop("checked", true);
|
||||||
|
$icon.removeClass().addClass("bi bi-check");
|
||||||
|
break;
|
||||||
|
case false:
|
||||||
|
$elem.find('input[type="checkbox"]').prop("checked", false);
|
||||||
|
$icon.removeClass().addClass("bi bi-x");
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
default:
|
||||||
|
$elem.find('input[type="checkbox"]').prop("checked", false);
|
||||||
|
$icon.removeClass().addClass("bi bi-dash");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function bindSearchBar(searchBarSelector, loadDataFunc) {
|
async function bindSearchBar(searchBarSelector, loadDataFunc) {
|
||||||
searchBar = $("#" + searchBarSelector)
|
searchBar = $("#" + searchBarSelector)
|
||||||
searchBar.on("input", async function() {
|
searchBar.on("input", async function() {
|
||||||
clearTimeout(timeouts[searchBarSelector]);
|
clearTimeout(timeouts[searchBarSelector]);
|
||||||
searchString = $(this).val();
|
var searchString = $(this).val();
|
||||||
timeouts[searchBarSelector] = setTimeout(async function() {
|
timeouts[searchBarSelector] = setTimeout(async function() {
|
||||||
await loadDataFunc(getCurrentlyActiveServer().guild_id, 1, null, searchString);
|
await loadDataFunc(getCurrentlyActiveServer().guild_id, 1, null, searchString);
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function bindFilterDropdown(filterDropdownId, loadDataFunc) {
|
||||||
|
$(`#${filterDropdownId} input`).on("change", function() {
|
||||||
|
alert($(this).attr("data-key"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createTable(containingSelector, tableId) {
|
function createTable(containingSelector, tableId) {
|
||||||
$(containingSelector).append(`
|
$(containingSelector).append(`
|
||||||
<div class="table-responsive my-3 px-3">
|
<div class="table-responsive my-3 px-3">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user