aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/assets/js/admin/tabs/files.js116
-rw-r--r--src/guff/apis.cr21
-rw-r--r--src/guff/models/file.cr37
-rw-r--r--src/guff/models/site.cr15
-rw-r--r--src/guff/views/pages/admin.cr6
5 files changed, 160 insertions, 35 deletions
diff --git a/data/assets/js/admin/tabs/files.js b/data/assets/js/admin/tabs/files.js
index 56fb6c9..bfd1943 100644
--- a/data/assets/js/admin/tabs/files.js
+++ b/data/assets/js/admin/tabs/files.js
@@ -49,7 +49,7 @@ jQuery(function($) {
"<div class='btn-group btn-group-sm'>",
"<a ",
"href='#' ",
- "class='btn btn-default btn-sm' ",
+ "class='crumb btn btn-default btn-sm' ",
"data-path='%{path|h}' ",
">",
"%{name|h}",
@@ -64,8 +64,62 @@ jQuery(function($) {
delete_confirm: [
"Are you sure you want to delete \"%{name|h}\"?",
],
+
+ sites: [
+ "<div class='btn-group btn-group-sm'>",
+ "<a ",
+ "href='#' ",
+ "class='btn btn-default' ",
+ "title='Choose site.' ",
+ "data-toggle='dropdown' ",
+ ">",
+ "Site: <span>%{name|h}</span>",
+ " ",
+ "<i class='fa fa-caret-down'></i>",
+ "</a>",
+
+ "<ul class='dropdown-menu'>",
+ "%{body}",
+ "</ul>",
+ "</div><!-- btn-group -->",
+ ],
+
+ site: [
+ "<li class='%{css|h}'>",
+ "<a ",
+ "href='#' ",
+ "title='%{text|h}' ",
+ "data-id='%{site_id|h}' ",
+ "data-name='%{name|h}' ",
+ ">",
+ "%{name|h}",
+ "</a>",
+ "</li>",
+ ],
});
+ function get_selected_site() {
+ var site_id = $('#files').data('site_id');
+
+ return $.grep(DATA.sites, function(row) {
+ return site_id == row.site_id;
+ })[0];
+ }
+
+ function make_site_dropdown() {
+ var curr_site = get_selected_site();
+
+ return TEMPLATES.run('sites', {
+ name: curr_site.name,
+ body: $.map(DATA.sites, function(row) {
+ return TEMPLATES.run('site', $.extend({}, row, {
+ css: (row.site_id == curr_site.site_id) ? 'active' : '',
+ text: 'Show files for this site.', // FIXME
+ }));
+ }).join(''),
+ });
+ }
+
function get_crumbs(path) {
var r = [];
@@ -83,17 +137,18 @@ jQuery(function($) {
var NO_FILES = TEMPLATES.run('no_files');
function reload() {
- var btn = $('#files-reload'),
+ var btns = $('#files-reload, #files-crumbs .btn'),
list = $('#files');
// show loading
- btn.toggleClass('disabled').find('.loading').toggleClass('hidden');
+ btns.toggleClass('disabled').find('.loading').toggleClass('hidden');
// list.html(TEMPLATES.run('loading'));
send('file/list', {
- path: $('#files').data('path')
+ site_id: $('#files').data('site_id'),
+ path: $('#files').data('path'),
}).always(function() {
- btn.toggleClass('disabled').find('.loading').toggleClass('hidden');
+ btns.toggleClass('disabled').find('.loading').toggleClass('hidden');
// list.html('');
}).fail(function(r) {
var error = r.responseText;
@@ -111,12 +166,14 @@ jQuery(function($) {
// draw crumbs
var crumbs = get_crumbs($('#files').data('path'));
- $('#files-crumbs').html($.map(crumbs, function(crumb) {
+ $('#files-crumbs').html([
+ make_site_dropdown()
+ ].concat($.map(crumbs, function(crumb) {
return TEMPLATES.run('crumb', {
path: crumb,
name: crumb.replace(/^.*\/(.+)/, '$1'),
});
- }).join(''));
+ })).join(''));
// draw files
$('#files').html((r.length > 0) ? $.map(r, function(row) {
@@ -160,7 +217,7 @@ jQuery(function($) {
return false;
});
- $('#files-crumbs').on('click', 'a.btn', function() {
+ $('#files-crumbs').on('click', 'a.crumb', function() {
$('#files').data('path', $(this).data('path'));
reload();
@@ -168,6 +225,33 @@ jQuery(function($) {
return false;
});
+ $('#files-crumbs').on('click', 'ul.dropdown-menu a', function() {
+ var data = $(this).data(),
+ ul = $(this).parents('ul');
+
+ // hide dropdown
+ $('body').trigger('click');
+
+ // refresh selection
+ ul.find('li.active').removeClass('active');
+ $(this).parent('li').addClass('active');
+
+ // update button text
+ ul.prev('a').find('span').text(data.name);
+
+ // save site id and path
+ $('#files').data({
+ site_id: data.id,
+ path: '/',
+ });
+
+ // reload file list
+ reload();
+
+ // stop event
+ return false;
+ });
+
$('#file-actions').on('click', 'a', function() {
var action_id = $(this).data('id'),
data = $('#files .active').data();
@@ -178,11 +262,12 @@ jQuery(function($) {
if (data) {
if (action_id == 'download') {
if (data.url)
- location.href = url;
+ location.href = data.url;
} else if (action_id == 'move') {
var dst_path = prompt(TEMPLATES.run('move_prompt', data), data.path);
if (dst_path) {
send('file/move', {
+ site_id: $('#files').data('site_id'),
src_path: data.path,
dst_path: dst_path,
}).always(function() {
@@ -205,7 +290,8 @@ jQuery(function($) {
} else if (action_id == 'delete') {
if (confirm(TEMPLATES.run('delete_confirm', data))) {
send('file/delete', {
- path: data.path,
+ site_id: $('#files').data('site_id'),
+ path: data.path,
}).always(function() {
// TODO: need loading handler
}).fail(function(r) {
@@ -253,7 +339,8 @@ jQuery(function($) {
me.toggleClass('disabled').find('.loading').toggleClass('hidden');
send('file/mkdir', {
- path: ($('#files').data('path') + '/' + path).replace(/\/\/+/, '/')
+ site_id: $('#files').data('site_id'),
+ path: ($('#files').data('path') + '/' + path).replace(/\/\/+/, '/')
}).always(function() {
// enable button, hide spinner
me.toggleClass('disabled').find('.loading').toggleClass('hidden');
@@ -276,7 +363,12 @@ jQuery(function($) {
return false;
});
- $('#files').data('path', '/');
+ // set defaults
+ $('#files').data({
+ path: '/',
+ site_id: DATA.default_site_id,
+ });
+
$('#files-reload').click(reload);
// load users
diff --git a/src/guff/apis.cr b/src/guff/apis.cr
index bbedd3f..f5424dd 100644
--- a/src/guff/apis.cr
+++ b/src/guff/apis.cr
@@ -190,26 +190,32 @@ module Guff::APIs
module FileAPI
def do_file_list(params : HTTP::Params)
- @context.models.file.list(URI.unescape(params["path"]))
+ @context.models.file.list(
+ site_id: params["site_id"].not_nil!.to_i64,
+ path: URI.unescape(params["path"]),
+ )
end
def do_file_add(params : HTTP::Params)
# TODO: upload data will be cached in context, then retreived in
# file model
@context.models.file.add(
- URI.unescape(params["path"].not_nil!),
- params["upload_data"].not_nil!,
+ site_id: params["site_id"].not_nil!.to_i64,
+ path: URI.unescape(params["path"].not_nil!),
+ upload_data: params["upload_data"].not_nil!,
)
end
def do_file_mkdir(params : HTTP::Params)
- # TODO: uploaded data is cached in context, then retreived in file
- # model
- @context.models.file.mkdir(URI.unescape(params["path"].not_nil!))
+ @context.models.file.mkdir(
+ site_id: params["site_id"].not_nil!.to_i64,
+ path: URI.unescape(params["path"].not_nil!),
+ )
end
def do_file_move(params : HTTP::Params)
@context.models.file.move(
+ site_id: params["site_id"].not_nil!.to_i64,
src_path: URI.unescape(params["src_path"].not_nil!),
dst_path: URI.unescape(params["dst_path"].not_nil!),
)
@@ -217,7 +223,8 @@ module Guff::APIs
def do_file_delete(params : HTTP::Params)
@context.models.file.delete(
- URI.unescape(params["path"].not_nil!),
+ site_id: params["site_id"].not_nil!.to_i64,
+ path: URI.unescape(params["path"].not_nil!),
)
end
end
diff --git a/src/guff/models/file.cr b/src/guff/models/file.cr
index b001c2f..f55037c 100644
--- a/src/guff/models/file.cr
+++ b/src/guff/models/file.cr
@@ -1,9 +1,9 @@
require "./model"
class Guff::Models::FileModel < Guff::Models::Model
- def list(path : String)
+ def list(site_id : Int64, path : String)
# build absolute path
- abs_path = expand_path(path)
+ abs_path = expand_path(site_id, path)
# make sure directory exists
unless Dir.exists?(abs_path)
@@ -11,8 +11,12 @@ class Guff::Models::FileModel < Guff::Models::Model
end
# build base file path
- base_path = File.expand_path(path)
- base_url = File.join("/guff/api/file/download", base_path)
+ base_path = File.expand_path(path, "/")
+ base_url = File.join(
+ "/guff/api/file/download",
+ @context.models.site.get_name(site_id),
+ base_path
+ )
Dir.entries(abs_path).select { |file|
# exclude hidden files
@@ -34,14 +38,18 @@ class Guff::Models::FileModel < Guff::Models::Model
}
end
- def add(path : String, upload_data : String)
+ def add(
+ site_id : Int64,
+ path : String,
+ upload_data : String
+ )
# TODO
nil
end
- def mkdir(path : String)
+ def mkdir(site_id : Int64, path : String)
# build absolute path
- abs_path = expand_path(path)
+ abs_path = expand_path(site_id, path)
# create directory
Dir.mkdir(abs_path)
@@ -49,10 +57,10 @@ class Guff::Models::FileModel < Guff::Models::Model
nil
end
- def move(src_path : String, dst_path : String)
+ def move(site_id : Int64, src_path : String, dst_path : String)
# build absolute paths
- abs_src_path = expand_path(src_path)
- abs_dst_path = expand_path(dst_path)
+ abs_src_path = expand_path(site_id, src_path)
+ abs_dst_path = expand_path(site_id, dst_path)
# make sure src path exists
unless File.exists?(abs_src_path)
@@ -71,9 +79,9 @@ class Guff::Models::FileModel < Guff::Models::Model
nil
end
- def delete(path : String)
+ def delete(site_id : Int64, path : String)
# build absolute path
- abs_path = expand_path(path)
+ abs_path = expand_path(site_id, path)
if Dir.exists?(abs_path)
Dir.rmdir(abs_path)
@@ -87,14 +95,15 @@ class Guff::Models::FileModel < Guff::Models::Model
nil
end
- private def expand_path(path : String)
+ private def expand_path(site_id : Int64, path : String)
raise "invalid path" if path.includes?('\0')
# return expanded path
File.join(
@context.config.data_dir,
"files",
- File.expand_path(path)
+ @context.models.site.get_name(site_id),
+ File.expand_path(path, "/")
)
end
end
diff --git a/src/guff/models/site.cr b/src/guff/models/site.cr
index 431911d..4672fa4 100644
--- a/src/guff/models/site.cr
+++ b/src/guff/models/site.cr
@@ -61,7 +61,16 @@ class Guff::Models::SiteModel < Guff::Models::Model
JOIN themes b
ON (b.theme_id = a.theme_id)
WHERE a.site_id = ?
- "
+ ",
+
+ get_name: "
+ SELECT name
+
+ FROM sites a
+
+ WHERE site_id = ?
+ AND is_active
+ ",
}
def get_id(host : String?) : Int64?
@@ -89,4 +98,8 @@ class Guff::Models::SiteModel < Guff::Models::Model
def get(site_id : Int64)
@context.dbs.ro.row(SQL[:get], [site_id.to_s]).not_nil!
end
+
+ def get_name(site_id : Int64) : String
+ @context.dbs.ro.one(SQL[:get_name], [site_id.to_s]).as(String)
+ end
end
diff --git a/src/guff/views/pages/admin.cr b/src/guff/views/pages/admin.cr
index e385cea..f2296a8 100644
--- a/src/guff/views/pages/admin.cr
+++ b/src/guff/views/pages/admin.cr
@@ -99,7 +99,11 @@ class Guff::Views::Pages::Admin < Guff::Views::HTMLView
end
private def page_data
- { post_types: POST_TYPES}.to_json
+ {
+ post_types: POST_TYPES,
+ sites: @context.models.site.get_sites,
+ default_site_id: @context.models.site.get_default_id,
+ }.to_json
end
ECR.def_to_s("src/views/pages/admin.ecr")