adding csp

This commit is contained in:
2021-04-30 19:37:56 +01:00
parent 5eecbf1075
commit d21ec61f06
10 changed files with 71 additions and 67 deletions

View File

@@ -146,6 +146,10 @@ BOOTSTRAP4 = {
"crossorigin": "anonymous", "crossorigin": "anonymous",
}, },
} }
CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", 'cdn.jsdelivr.net', 'cdn.datatables.net', 'i.creativecommons.org', CSP_DEFAULT_SRC = ("'none'")
'code.jquery.com', 'licensebuttons.net', 'www.w3.org') CSP_STYLE_SRC = ("'self'", 'cdn.jsdelivr.net', 'cdn.datatables.net')
CSP_IMG_SRC = ("'self'", 'i.creativecommons.org', 'licensebuttons.net') CSP_IMG_SRC = ("'self'", "data:")
CSP_FONT_SRC = ("'self'")
CSP_SCRIPT_SRC = ("'self'", 'code.jquery.com', 'cdn.jsdelivr.net', 'cdn.datatables.net')
CSP_CONNECT_SRC = ("'self'")
CSP_INCLUDE_NONCE_IN = ['script-src']

View File

@@ -12,7 +12,7 @@ import fitz
import rarfile import rarfile
from PIL import Image, UnidentifiedImageError from PIL import Image, UnidentifiedImageError
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User, AbstractUser
from django.core.files.uploadedfile import InMemoryUploadedFile from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db import models from django.db import models
from django.db.transaction import atomic from django.db.transaction import atomic

View File

@@ -11,13 +11,13 @@
<meta name="author" content="Ajurna"> <meta name="author" content="Ajurna">
<link rel="icon" href="{% static "favicon.ico" %}"> <link rel="icon" href="{% static "favicon.ico" %}">
<title>{% block title %}CB Reader{% endblock %}</title> <title>{% block title %}CB Web Reader{% endblock %}</title>
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
{% bootstrap_css %} {% bootstrap_css %}
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.21/b-1.6.2/b-colvis-1.6.2/r-2.2.4/datatables.min.css"/> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.21/b-1.6.2/b-colvis-1.6.2/r-2.2.4/datatables.min.css"/>
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
<link href="{% static "css/base.css" %}" rel="stylesheet"> <link href="{% static "css/base.min.css" %}" rel="stylesheet">
<link href="{% static "font-awesome/css/all.css" %}" rel="stylesheet"> <link href="{% static "font-awesome/css/all.css" %}" rel="stylesheet">
{# <link href="{% static "reveal.js/css/reveal.css" %}" rel="stylesheet">#} {# <link href="{% static "reveal.js/css/reveal.css" %}" rel="stylesheet">#}
@@ -28,7 +28,7 @@
<body> <body>
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/"><img src="{% static 'img/logo.svg' %}" class="d-inline-block align-top" height="35px"> Web Reader</a> <a class="navbar-brand" href="/"><img src="{% static 'img/logo.svg' %}" class="d-inline-block align-top" height="35px" alt="CB"> Web Reader</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
@@ -56,7 +56,7 @@
<!-- /.container --> <!-- /.container -->
<footer class="footer mt-auto py-3"> <footer class="footer mt-auto py-3">
<div class="container text-center"> <div class="container text-center">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons Licence" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/InteractiveResource" property="dct:title" rel="dct:type">CBReader</span> by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Ajurna</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.<br />Based on a work at <a xmlns:dct="http://purl.org/dc/terms/" href="https://github.com/ajurna/cbreader" rel="dct:source">https://github.com/ajurna/cbreader</a>. <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons Licence" src="{% static "img/ccbysa.png" %}" /></a><br /><span xmlns:dct="https://purl.org/dc/terms/" href="https://purl.org/dc/dcmitype/InteractiveResource" property="dct:title" rel="dct:type">CBReader</span> by <span xmlns:cc="https://creativecommons.org/ns#" property="cc:attributionName">Ajurna</span> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.<br />Based on a work at <a xmlns:dct="https://purl.org/dc/terms/" href="https://github.com/ajurna/cbreader" rel="dct:source">https://github.com/ajurna/cbreader</a>.
</div> </div>
</footer> </footer>

View File

@@ -8,7 +8,7 @@
<div class="row"> <div class="row">
<div class="input-group"> <div class="input-group">
<input type="text" id="quicksearch" class="form-control" placeholder="Search" aria-label="Search list of comics" aria-describedby="button-addon4"> <input type="text" id="quicksearch" class="form-control" placeholder="Search" aria-label="Search list of comics" aria-describedby="button-addon4">
<div id="filters" class="input-group-append" id="button-addon4"> <div id="filters" class="input-group-append">
<button class="btn btn-outline-secondary filters" type="button" data-filter="*">All</button> <button class="btn btn-outline-secondary filters" type="button" data-filter="*">All</button>
<button class="btn btn-outline-secondary filters" type="button" data-filter=".read">Read</button> <button class="btn btn-outline-secondary filters" type="button" data-filter=".read">Read</button>
<button class="btn btn-outline-secondary filters" type="button" data-filter=".unread">Unread</button> <button class="btn btn-outline-secondary filters" type="button" data-filter=".unread">Unread</button>
@@ -17,8 +17,8 @@
Actions Actions
</button> </button>
<div class="dropdown-menu" aria-labelledby="btnGroupDrop1"> <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<button type="button" class="btn btn-primary dropdown-item" title="Mark Un-Read" onclick="comic_action('{{ selector }}', 'Directory', 'mark_unread')"><i class="fas fa-book">Mark Un-Read</i></button> <button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Un-Read" selector="{{ selector }}" itemtype="Directory" comic_action="mark_unread"><i class="fas fa-book">Mark Un-Read</i></button>
<button type="button" class="btn btn-primary dropdown-item" title="Mark Read" onclick="comic_action('{{ selector }}', 'Directory', 'mark_read')"><i class="fas fa-book-open">Mark Read</i></button> <button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Read" selector="{{ selector }}" itemtype="Directory" comic_action="mark_read"><i class="fas fa-book-open">Mark Read</i></button>
{# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#} {# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#}
</div> </div>
</div> </div>
@@ -30,7 +30,7 @@
<div class="row grid "> <div class="row grid ">
{% for file in files %} {% for file in files %}
<div class="m-2 grid-item {% if file.percent == 100 %}read{% else %}unread{% endif %}"> <div class="m-2 grid-item {% if file.percent == 100 %}read{% else %}unread{% endif %}">
<div class="card" style="width: 200px;"> <div class="card card_list_card">
{% if file.item_type == 'Directory' %} {% if file.item_type == 'Directory' %}
<a href="{% url "comic_list" file.selector %}"> <a href="{% url "comic_list" file.selector %}">
{% elif file.item_type == 'ComicBook' %} {% elif file.item_type == 'ComicBook' %}
@@ -58,28 +58,33 @@
</a> </a>
</h5> </h5>
<p class="card-text"> <p class="card-text">
<figure class="text-center w-100 mb-0">{{ file.total_read }} / {{ file.total }}</figure>
<div class="progress"> <div class="progress">
<div class="progress-bar" role="progressbar" style="width: {{ file.percent }}%;" aria-valuenow="{{ file.percent }}" aria-valuemin="0" aria-valuemax="100">{{ file.percent }}%</div> <div class="progress-bar" role="progressbar" aria-valuenow="{{ file.percent }}" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
</p> </p>
<div class="btn-group" role="group" aria-label="Comic Actions"> <div class="btn-group" role="group" aria-label="Comic Actions">
<button type="button" class="btn btn-primary" title="Mark Un-Read" onclick="comic_action('{{ file.selector }}', '{{ file.item_type }}', 'mark_unread')"><i class="fas fa-book"></i></button> <button type="button" class="btn btn-primary comic_action" title="Mark Un-Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_unread"><i class="fas fa-book"></i></button>
<button type="button" class="btn btn-primary" title="Mark Read" onclick="comic_action('{{ file.selector }}', '{{ file.item_type }}', 'mark_read')"><i class="fas fa-book-open"></i></button> <button type="button" class="btn btn-primary comic_action" title="Mark Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_read"><i class="fas fa-book-open"></i></button>
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
</button> </button>
<div class="dropdown-menu" aria-labelledby="btnGroupDrop1"> <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<button type="button" class="btn btn-primary dropdown-item" title="Mark Un-Read" onclick="comic_action('{{ file.selector }}', '{{ file.item_type }}', 'mark_unread')"><i class="fas fa-book">Mark Un-Read</i></button> <button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Un-Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_unread"><i class="fas fa-book">Mark Un-Read</i></button>
<button type="button" class="btn btn-primary dropdown-item" title="Mark Read" onclick="comic_action('{{ file.selector }}', '{{ file.item_type }}', 'mark_read')"><i class="fas fa-book-open">Mark Read</i></button> <button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_read"><i class="fas fa-book-open">Mark Read</i></button>
{% if file.item_type != 'Directory' %} {% if file.item_type != 'Directory' %}
<button type="button" class="btn btn-primary dropdown-item" title="Mark Previous Read"><i class="fas fa-book" onclick="comic_action('{{ file.selector }}', '{{ file.item_type }}', 'mark_previous')"><i class="fas fa-arrow-up">Mark Previous Read</i></i></button> <button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Previous Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_previous"><i class="fas fa-book"><i class="fas fa-arrow-up">Mark Previous Read</i></i></button>
{% endif %} {% endif %}
{# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#} {# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#}
</div> </div>
</div> </div>
</div> </div>
{% if file.total_unread and file.item_type == 'Directory' %}
<span class="badge rounded-pill bg-primary card-badge">{{ file.total_unread }}</span>
{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -86,6 +86,9 @@ class DirFile:
item_type: str = '' item_type: str = ''
percent: int = 0 percent: int = 0
selector: str = '' selector: str = ''
total: int = None
total_read: int = None
total_unread: int = None
def __post_init__(self): def __post_init__(self):
self.item_type = type(self.obj).__name__ self.item_type = type(self.obj).__name__
@@ -94,10 +97,14 @@ class DirFile:
total_adjustment = 1 total_adjustment = 1
if isinstance(self.obj, Directory): if isinstance(self.obj, Directory):
total_adjustment = 0 total_adjustment = 0
self.total = self.obj.total - total_adjustment
self.total_read = self.obj.total_read
self.total_unread = self.total - self.total_read
try: try:
self.percent = int((self.obj.total_read / (self.obj.total - total_adjustment)) * 100) self.percent = int((self.obj.total_read / self.total) * 100)
except ZeroDivisionError: except ZeroDivisionError:
self.percent = 0 self.percent = 0
self.selector = self.obj.url_safe_selector self.selector = self.obj.url_safe_selector
if isinstance(self.obj, Directory): if isinstance(self.obj, Directory):
self.name = self.obj.name self.name = self.obj.name

View File

@@ -1,46 +1,14 @@
/*.navbar {*/
/* margin: 0px;*/
/*}*/
/*.starter-template {*/
/* padding: 40px 15px;*/
/* text-align: center;*/
/*}*/
/*!* Sticky footer styles*/
/*-------------------------------------------------- *!*/
/*html {*/
/* position: relative;*/
/* min-height: 100%;*/
/*}*/
/*body {*/
/* !* Margin bottom by footer height *!*/
/* margin-bottom: 80px;*/
/*}*/
/*.footer {*/
/* position: absolute;*/
/* bottom: 0;*/
/* width: 100%;*/
/* !* Set the fixed height of the footer here *!*/
/* height: 80px;*/
/* background-color: #f5f5f5;*/
/*}*/
/*.comic_box {*/
/* width: 100%;*/
/*}*/
/*#dropdown-list{*/
/* max-height: 300px;*/
/* overflow: auto;*/
/* box-shadow: none;*/
/* }*/
/* td a {*/
/* display:block;*/
/* width:100%;*/
/* }*/
/* tr.clickable-row {*/
/* cursor: pointer;*/
/* }*/
#comic_list caption { #comic_list caption {
caption-side: top; caption-side: top;
} }
.card_list_card {
width: 200px;
}
.card .card-badge {
position:absolute;
top:10px;
left:10px;
padding:5px;
color:white;
}

1
static/css/base.min.css vendored Normal file
View File

@@ -0,0 +1 @@
#comic_list caption{caption-side:top}.card_list_card{width:200px}.card .card-badge{position:absolute;top:10px;left:10px;padding:5px;color:#fff}

BIN
static/img/ccbysa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -11,9 +11,13 @@ var buttonFilter;
} }
}); });
$('#filters').on( 'click', 'button', function() { $('#filters').on( 'click', 'button', function() {
if (typeof $( this ).attr('data-filter') === "undefined") {
}else {
buttonFilter = $( this ).attr('data-filter'); buttonFilter = $( this ).attr('data-filter');
sessionStorage.setItem(window.location.href+"button", buttonFilter); sessionStorage.setItem(window.location.href+"button", buttonFilter);
$grid.isotope(); $grid.isotope();
}
}); });
var $quicksearch = $('#quicksearch').keyup( debounce( function() { var $quicksearch = $('#quicksearch').keyup( debounce( function() {
@@ -65,3 +69,18 @@ function comic_action(selector, item_type, action) {
}) })
} }
$( ".progress-bar" ).each(function( index ) {
let bar = $(this)
bar.css('width', bar.attr('aria-valuenow') + '%')
});
let comic_action_elements = document.getElementsByClassName('comic_action')
comic_action_elements.forEach(el => el.addEventListener('click', event => {
let target = $(event.target).closest('button')
let selector = target.attr('selector')
let item_type = target.attr('itemtype')
let action = target.attr('comic_action')
comic_action(selector, item_type, action)
}));

View File

@@ -1 +1 @@
var qsRegex;var buttonFilter;var $grid=$(".comic-container").isotope({itemSelector:".grid-item",layoutMode:"fitRows",filter:function(){var $this=$(this);var searchResult=qsRegex?$this.text().match(qsRegex):true;var buttonResult=buttonFilter?$this.is(buttonFilter):true;return searchResult&&buttonResult}});$("#filters").on("click","button",function(){buttonFilter=$(this).attr("data-filter");sessionStorage.setItem(window.location.href+"button",buttonFilter);$grid.isotope()});var $quicksearch=$("#quicksearch").keyup(debounce(function(){qsRegex=new RegExp($quicksearch.val(),"gi");sessionStorage.setItem(window.location.href+"text",$quicksearch.val());$grid.isotope()}));function debounce(fn,threshold){var timeout;threshold=threshold||100;return function debounced(){clearTimeout(timeout);var args=arguments;var _this=this;function delayed(){fn.apply(_this,args)}timeout=setTimeout(delayed,threshold)}}setInterval(function(){$grid.isotope()},1e3);let field=document.getElementById("quicksearch");if(sessionStorage.getItem(window.location.href+"text")||sessionStorage.getItem(window.location.href+"button")){field.value=sessionStorage.getItem(window.location.href+"text");qsRegex=new RegExp($quicksearch.val(),"gi");buttonFilter=sessionStorage.getItem(window.location.href+"button");$grid.isotope()}field.addEventListener("change",function(){});function comic_action(selector,item_type,action){$.ajax({url:"/comic/action/"+action+"/"+item_type+"/"+selector+"/",success:function(){window.location.reload()}})} var qsRegex;var buttonFilter;var $grid=$(".comic-container").isotope({itemSelector:".grid-item",layoutMode:"fitRows",filter:function(){var $this=$(this);var searchResult=qsRegex?$this.text().match(qsRegex):true;var buttonResult=buttonFilter?$this.is(buttonFilter):true;return searchResult&&buttonResult}});$("#filters").on("click","button",function(){if(typeof $(this).attr("data-filter")==="undefined"){}else{buttonFilter=$(this).attr("data-filter");sessionStorage.setItem(window.location.href+"button",buttonFilter);$grid.isotope()}});var $quicksearch=$("#quicksearch").keyup(debounce(function(){qsRegex=new RegExp($quicksearch.val(),"gi");sessionStorage.setItem(window.location.href+"text",$quicksearch.val());$grid.isotope()}));function debounce(fn,threshold){var timeout;threshold=threshold||100;return function debounced(){clearTimeout(timeout);var args=arguments;var _this=this;function delayed(){fn.apply(_this,args)}timeout=setTimeout(delayed,threshold)}}setInterval(function(){$grid.isotope()},1e3);let field=document.getElementById("quicksearch");if(sessionStorage.getItem(window.location.href+"text")||sessionStorage.getItem(window.location.href+"button")){field.value=sessionStorage.getItem(window.location.href+"text");qsRegex=new RegExp($quicksearch.val(),"gi");buttonFilter=sessionStorage.getItem(window.location.href+"button");$grid.isotope()}field.addEventListener("change",function(){});function comic_action(selector,item_type,action){$.ajax({url:"/comic/action/"+action+"/"+item_type+"/"+selector+"/",success:function(){window.location.reload()}})}$(".progress-bar").each(function(index){let bar=$(this);bar.css("width",bar.attr("aria-valuenow")+"%")});let comic_action_elements=document.getElementsByClassName("comic_action");comic_action_elements.forEach(el=>el.addEventListener("click",event=>{let target=$(event.target).closest("button");let selector=target.attr("selector");let item_type=target.attr("itemtype");let action=target.attr("comic_action");comic_action(selector,item_type,action)}));