mirror of
https://github.com/ajurna/cbwebreader.git
synced 2025-12-06 06:17:17 +00:00
adding csp
This commit is contained in:
@@ -146,6 +146,10 @@ BOOTSTRAP4 = {
|
||||
"crossorigin": "anonymous",
|
||||
},
|
||||
}
|
||||
CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", 'cdn.jsdelivr.net', 'cdn.datatables.net', 'i.creativecommons.org',
|
||||
'code.jquery.com', 'licensebuttons.net', 'www.w3.org')
|
||||
CSP_IMG_SRC = ("'self'", 'i.creativecommons.org', 'licensebuttons.net')
|
||||
CSP_DEFAULT_SRC = ("'none'")
|
||||
CSP_STYLE_SRC = ("'self'", 'cdn.jsdelivr.net', 'cdn.datatables.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']
|
||||
@@ -12,7 +12,7 @@ import fitz
|
||||
import rarfile
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
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.db import models
|
||||
from django.db.transaction import atomic
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<meta name="author" content="Ajurna">
|
||||
<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_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 -->
|
||||
<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 "reveal.js/css/reveal.css" %}" rel="stylesheet">#}
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<body>
|
||||
<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">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
@@ -56,7 +56,7 @@
|
||||
<!-- /.container -->
|
||||
<footer class="footer mt-auto py-3">
|
||||
<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>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="row">
|
||||
<div class="input-group">
|
||||
<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=".read">Read</button>
|
||||
<button class="btn btn-outline-secondary filters" type="button" data-filter=".unread">Unread</button>
|
||||
@@ -17,8 +17,8 @@
|
||||
Actions
|
||||
</button>
|
||||
<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" 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 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 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>#}
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,10 +27,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="container comic-container">
|
||||
<div class="row grid">
|
||||
<div class="row grid ">
|
||||
{% for file in files %}
|
||||
<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' %}
|
||||
<a href="{% url "comic_list" file.selector %}">
|
||||
{% elif file.item_type == 'ComicBook' %}
|
||||
@@ -58,28 +58,33 @@
|
||||
</a>
|
||||
</h5>
|
||||
<p class="card-text">
|
||||
<figure class="text-center w-100 mb-0">{{ file.total_read }} / {{ file.total }}</figure>
|
||||
<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>
|
||||
</p>
|
||||
<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" 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 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 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">
|
||||
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
|
||||
</button>
|
||||
<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" 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 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 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' %}
|
||||
<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 %}
|
||||
{# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#}
|
||||
</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>
|
||||
|
||||
@@ -86,6 +86,9 @@ class DirFile:
|
||||
item_type: str = ''
|
||||
percent: int = 0
|
||||
selector: str = ''
|
||||
total: int = None
|
||||
total_read: int = None
|
||||
total_unread: int = None
|
||||
|
||||
def __post_init__(self):
|
||||
self.item_type = type(self.obj).__name__
|
||||
@@ -94,10 +97,14 @@ class DirFile:
|
||||
total_adjustment = 1
|
||||
if isinstance(self.obj, Directory):
|
||||
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:
|
||||
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:
|
||||
self.percent = 0
|
||||
|
||||
self.selector = self.obj.url_safe_selector
|
||||
if isinstance(self.obj, Directory):
|
||||
self.name = self.obj.name
|
||||
|
||||
@@ -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 {
|
||||
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
1
static/css/base.min.css
vendored
Normal 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
BIN
static/img/ccbysa.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -11,9 +11,13 @@ var buttonFilter;
|
||||
}
|
||||
});
|
||||
$('#filters').on( 'click', 'button', function() {
|
||||
buttonFilter = $( this ).attr('data-filter');
|
||||
sessionStorage.setItem(window.location.href+"button", buttonFilter);
|
||||
$grid.isotope();
|
||||
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() {
|
||||
@@ -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)
|
||||
}));
|
||||
2
static/js/comic_list.min.js
vendored
2
static/js/comic_list.min.js
vendored
@@ -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)}));
|
||||
Reference in New Issue
Block a user