mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-24 10:37:23 +00:00
Server side file browser
This commit is contained in:
parent
2508c1abb2
commit
d3986ca14a
35
cps/admin.py
35
cps/admin.py
@ -520,13 +520,21 @@ def list_restriction(res_type):
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
return response
|
||||
|
||||
@admi.route("/basicconfig/pathchooser/")
|
||||
@unconfigured
|
||||
def config_pathchooser():
|
||||
return pathchooser()
|
||||
|
||||
@admi.route("/ajax/pathchooser/", endpoint="pathchooser")
|
||||
@admi.route("/ajax/filechooser/", endpoint="filechooser")
|
||||
@admi.route("/ajax/pathchooser/")
|
||||
@login_required
|
||||
@admin_required
|
||||
def ajax_pathchooser():
|
||||
return pathchooser()
|
||||
|
||||
def pathchooser():
|
||||
browse_for = "folder" if request.endpoint == "admin.pathchooser" else "file"
|
||||
browse_for = "folder" # if request.endpoint == "admin.pathchooser" else "file"
|
||||
folder_only = request.args.get('folder', False) == "true"
|
||||
file_filter = request.args.get('filter', "")
|
||||
path = os.path.normpath(request.args.get('path', ""))
|
||||
|
||||
if os.path.isfile(path):
|
||||
@ -538,11 +546,11 @@ def pathchooser():
|
||||
abs = False
|
||||
|
||||
if os.path.isdir(path):
|
||||
if os.path.isabs(path):
|
||||
cwd = os.path.realpath(path)
|
||||
abs = True
|
||||
else:
|
||||
cwd = os.path.relpath(path)
|
||||
#if os.path.isabs(path):
|
||||
cwd = os.path.realpath(path)
|
||||
abs = True
|
||||
#else:
|
||||
# cwd = os.path.relpath(path)
|
||||
else:
|
||||
cwd = os.getcwd()
|
||||
|
||||
@ -564,18 +572,19 @@ def pathchooser():
|
||||
folders = []
|
||||
|
||||
files = []
|
||||
locale = get_locale()
|
||||
# locale = get_locale()
|
||||
for f in folders:
|
||||
try:
|
||||
data = {"name": f, "fullpath": os.path.join(cwd, f)}
|
||||
data["sort"] = data["fullpath"].lower()
|
||||
data["modified"] = format_datetime(datetime.fromtimestamp(int(os.path.getmtime(os.path.join(cwd, f)))),
|
||||
format='short', locale=locale)
|
||||
data["ext"] = os.path.splitext(f)[1]
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if os.path.isfile(os.path.join(cwd, f)):
|
||||
if folder_only:
|
||||
continue
|
||||
if file_filter != "" and file_filter != f:
|
||||
continue
|
||||
data["type"] = "file"
|
||||
data["size"] = os.path.getsize(os.path.join(cwd, f))
|
||||
|
||||
@ -604,7 +613,7 @@ def pathchooser():
|
||||
return json.dumps(context)
|
||||
|
||||
|
||||
@admi.route("/config", methods=["GET", "POST"])
|
||||
@admi.route("/basicconfig", methods=["GET", "POST"])
|
||||
@unconfigured
|
||||
def basic_configuration():
|
||||
logout_user()
|
||||
|
@ -213,22 +213,33 @@ $(function() {
|
||||
});
|
||||
}
|
||||
|
||||
function fillFileTable(path, type) {
|
||||
if (type === "dir") {
|
||||
var request_path = "/../../ajax/pathchooser/";
|
||||
function fillFileTable(path, type, folder, filt) {
|
||||
if (window.location.pathname.endsWith("/basicconfig")) {
|
||||
var request_path = "/../basicconfig/pathchooser/";
|
||||
} else {
|
||||
var request_path = "/../../ajax/filechooser/";
|
||||
var request_path = "/../../ajax/pathchooser/";
|
||||
}
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
data: {
|
||||
path: path,
|
||||
folder: folder,
|
||||
filter: filt
|
||||
},
|
||||
url: window.location.pathname + request_path,
|
||||
success: function success(data) {
|
||||
if ($("#element_selected").text() ==="") {
|
||||
$("#element_selected").text(data.cwd);
|
||||
}
|
||||
$("#file_table > tbody > tr").each(function () {
|
||||
if ($(this).attr("id") !== "parent") {
|
||||
$(this).closest("tr").remove();
|
||||
} else {
|
||||
if(data.absolute && data.parentdir !== "") {
|
||||
$(this)[0].attributes['data-path'].value = data.parentdir;
|
||||
} else {
|
||||
$(this)[0].attributes['data-path'].value = "..";
|
||||
}
|
||||
}
|
||||
});
|
||||
if (data.parentdir !== "") {
|
||||
@ -444,83 +455,42 @@ $(function() {
|
||||
|
||||
|
||||
$("#fileModal").on("show.bs.modal", function(e) {
|
||||
//get data-id attribute of the clicked element and store in button
|
||||
//var submit = true;
|
||||
//var cwd = "{{oldfile|default(cwd, True)|abspath|replace('\\', '\\\\')}}";
|
||||
//var isabsolute = true;
|
||||
fillFileTable("","dir");
|
||||
var target = $(e.relatedTarget);
|
||||
var path = $("#" + target.data("link"))[0].value;
|
||||
var folder = target.data("folderonly");
|
||||
var filter = target.data("filefilter");
|
||||
$("#element_selected").text(path);
|
||||
$("#file_confirm")[0].attributes["data-link"].value = target.data("link");
|
||||
$("#file_confirm")[0].attributes["data-folderonly"].value = (typeof folder === 'undefined') ? false : true;
|
||||
$("#file_confirm")[0].attributes["data-filefilter"].value = (typeof filter === 'undefined') ? "" : filter;
|
||||
$("#file_confirm")[0].attributes["data-newfile"].value = target.data("newfile");
|
||||
fillFileTable(path,"dir", folder, filter);
|
||||
});
|
||||
|
||||
$("#file_confirm").click(function() {
|
||||
$("#" + $(this).data("link"))[0].value = $("#element_selected").text()
|
||||
});
|
||||
|
||||
//(".tr-clickable").on("click",
|
||||
$(document).on("click", ".tr-clickable", function() {
|
||||
var path = this.attributes['data-path'].value;
|
||||
var type = this.attributes['data-type'].value;
|
||||
fillFileTable(path, type);
|
||||
var path = this.attributes["data-path"].value;
|
||||
var type = this.attributes["data-type"].value;
|
||||
var folder = $(file_confirm).data("folderonly");
|
||||
var filter = $(file_confirm).data("filefilter");
|
||||
var newfile = $(file_confirm).data("newfile");
|
||||
if (newfile !== 'undefined') {
|
||||
$("#element_selected").text(path + $("#new_file".text()));
|
||||
} else {
|
||||
$("#element_selected").text(path);
|
||||
}
|
||||
if(type === "dir") {
|
||||
fillFileTable(path, type, folder, filter);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*{% if type == 'folder' %} {# browsing for folder #}
|
||||
var abspath = "{{url_for('app.pathchooser') + '?path=' + cwd|abspath|quote_plus}}";
|
||||
var relpath = "{{url_for('app.pathchooser') + '?path=' + cwd|relpath|quote_plus}}";
|
||||
{% else %} {# browsing for file #}
|
||||
var abspath = "{{url_for('app.filechooser') + '?path=' + oldfile|default(cwd, True)|abspath|quote_plus}}";
|
||||
var relpath = "{{url_for('app.filechooser') + '?path=' + oldfile|default(cwd, True)|relpath|quote_plus}}";
|
||||
{% endif %}*/
|
||||
/*document.addEventListener("readystatechange", function(event) {
|
||||
if (this.readyState === "complete") {
|
||||
document.getElementById("tbody").style.height = (window.innerHeight - 25) + "px";
|
||||
window.onresize = function (event) {
|
||||
document.getElementById("tbody").style.height = (window.innerHeight - 25) + "px";
|
||||
};
|
||||
var clickables = document.getElementsByClassName("tr-clickable");
|
||||
for (var i = 0; i < clickables.length; i++) {
|
||||
clickables[i].onclick = (function () {
|
||||
var onclick = clickables[i].onclick;
|
||||
return function (e) {
|
||||
if (onclick != null && !onclick()) {
|
||||
return false
|
||||
}
|
||||
if (this.dataset.href !== undefined && this.dataset.href !== "#") {
|
||||
window.location.href = this.dataset.href;
|
||||
return false
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
});
|
||||
function updateParent()
|
||||
{
|
||||
if (window.top.SettingsUI !== undefined) {
|
||||
window.top.SettingsUI.prototype.pathchooserChanged(this);
|
||||
}
|
||||
}
|
||||
function setInvalid() {
|
||||
submit = false;
|
||||
cwd = "";
|
||||
updateParent();
|
||||
}
|
||||
function setValid() {
|
||||
submit = true;
|
||||
updateParent();
|
||||
}
|
||||
function setFile(fullpath, name)
|
||||
{
|
||||
cwd = fullpath;
|
||||
/*{*% if type == "file" %} {# browsing for file #}
|
||||
abspath = "{{url_for('app.filechooser')}}?path={{cwd|abspath|quote_plus}}" + encodeURIComponent(name);
|
||||
relpath = "{{url_for('app.filechooser')}}?path={{cwd|relpath|quote_plus}}" + encodeURIComponent(name);
|
||||
{% endif %}*/
|
||||
/*setValid();
|
||||
}*/
|
||||
|
||||
$("#btndeletetoken").click(function() {
|
||||
//get data-id attribute of the clicked element
|
||||
var pathname = document.getElementsByTagName("script"), src = pathname[pathname.length - 1].src;
|
||||
var path = src.substring(0, src.lastIndexOf("/"));
|
||||
// var domainId = $(this).value("domainId");
|
||||
$.ajax({
|
||||
method:"get",
|
||||
url: path + "/../../kobo_auth/deleteauthtoken/" + this.value,
|
||||
|
@ -19,7 +19,7 @@
|
||||
<div class="form-group required input-group">
|
||||
<input type="text" class="form-control" id="config_calibre_dir" name="config_calibre_dir" value="{% if config.config_calibre_dir != None %}{{ config.config_calibre_dir }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" data-toggle="modal" id="converter_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
{% if feature_support['gdrive'] %}
|
||||
@ -94,14 +94,14 @@
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_certfile" name="config_certfile" value="{% if config.config_certfile != None %}{{ config.config_certfile }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="certfile_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" data-toggle="modal" data-link="config_certfile" data-target="#fileModal" id="certfile_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<label for="config_calibre_dir" >{{_('SSL Keyfile location (leave it empty for non-SSL Servers)')}}</label>
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_keyfile" name="config_keyfile" value="{% if config.config_keyfile != None %}{{ config.config_keyfile }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="keyfile_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="keyfile_path" data-toggle="modal" data-link="config_keyfile" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -268,21 +268,21 @@
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_ldap_cacert_path" name="config_ldap_cacert_path" value="{% if config.config_ldap_cacert_path != None %}{{ config.config_ldap_cacert_path }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="library_path" data-toggle="modal" data-link="config_ldap_cacert_path" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<label for="config_ldap_cert_path">{{_('LDAP Certificate Path (Only needed for Client Certificate Authentication)')}}</label>
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_ldap_cert_path" name="config_ldap_cert_path" value="{% if config.config_ldap_cert_path != None %}{{ config.config_ldap_cert_path }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="library_path" data-toggle="modal" data-link="config_ldap_cert_path" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<label for="config_ldap_key_path">{{_('LDAP Keyfile Path (Only needed for Client Certificate Authentication)')}}</label>
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_ldap_key_path" name="config_ldap_key_path" value="{% if config.config_ldap_key_path != None %}{{ config.config_ldap_key_path }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="library_path" data-toggle="modal" data-link="config_ldap_key_path" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -384,7 +384,7 @@
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_converterpath" name="config_converterpath" value="{% if config.config_converterpath != None %}{{ config.config_converterpath }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="converter_modal_path" data-toggle="modal" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" data-toggle="modal" id="converter_modal_path" data-link="config_converterpath" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -395,7 +395,7 @@
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_kepubifypath" name="config_kepubifypath" value="{% if config.config_kepubifypath != None %}{{ config.config_kepubifypath }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="kepubify_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="kepubify_path" data-toggle="modal" data-link="config_kepubifypath" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
{% if feature_support['rar'] %}
|
||||
@ -403,7 +403,7 @@
|
||||
<div class="form-group input-group">
|
||||
<input type="text" class="form-control" id="config_rarfile_location" name="config_rarfile_location" value="{% if config.config_rarfile_location != None %}{{ config.config_rarfile_location }}{% endif %}" autocomplete="off">
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="unrar_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
<button type="button" id="unrar_path" data-toggle="modal" data-link="config_rarfile_location" data-target="#fileModal" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -94,7 +94,8 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn btn-primary" value="{{_('Select')}}" name="file_confirm" id="file_confirm" data-dismiss="modal">
|
||||
<div class="text-left" id="element_selected"></div>
|
||||
<input type="button" class="btn btn-primary" data-path="" data-link="" data-folderonly="" data-filefilter="" data-newfile="" value="{{_('Select')}}" name="file_confirm" id="file_confirm" data-dismiss="modal">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -304,7 +304,7 @@ def before_request():
|
||||
g.shelves_access = ub.session.query(ub.Shelf).filter(
|
||||
or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all()
|
||||
if not config.db_configured and request.endpoint not in (
|
||||
'admin.basic_configuration', 'login') and '/static/' not in request.path:
|
||||
'admin.basic_configuration', 'login', "admin.config_pathchooser") and '/static/' not in request.path:
|
||||
return redirect(url_for('admin.basic_configuration'))
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user