diff options
-rw-r--r-- | data/assets/js/admin/tabs/posts.js | 42 | ||||
-rw-r--r-- | src/guff.cr | 203 | ||||
-rw-r--r-- | src/views/admin-page.ecr | 70 |
3 files changed, 228 insertions, 87 deletions
diff --git a/data/assets/js/admin/tabs/posts.js b/data/assets/js/admin/tabs/posts.js index 6bd4c4c..f2e082d 100644 --- a/data/assets/js/admin/tabs/posts.js +++ b/data/assets/js/admin/tabs/posts.js @@ -23,22 +23,31 @@ jQuery(function($) { "</td>", "<td>", - "<a href='#' ", - "class='edit-user' ", - "title='Edit user %{user_name|h}.' ", - "data-user_id='%{user_id|h}' ", + "<a ", + "href='#' ", + "class='edit' ", + "title='Edit site \"%{site_name|h}\".' ", + "data-edit='site' ", + "data-site_id='%{site_id|h}' ", ">", - "%{user_name|h}", + "%{site_name|h}", "</a>", "</td>", "<td>", - // TODO: make editable - "%{site_name|h}", + "%{post_url}", "</td>", "<td>", - "%{post_url}", + "<a ", + "href='#' ", + "class='edit' ", + "title='Edit user \"%{user_name|h}\".' ", + "data-edit='user' ", + "data-user_id='%{user_id|h}' ", + ">", + "%{user_name|h}", + "</a>", "</td>", "<td title='%{created_at_text_full|h}'>", @@ -106,10 +115,11 @@ jQuery(function($) { .find('.loading').toggleClass('hidden'); send('post/get_posts', { - type: $('#posts-filter-type li.active a').data('id'), - state: $('#posts-filter-state li.active a').data('id'), - q: $('#posts-q').data('q'), - page: 1, + type: $('#posts-filter-type li.active a').data('id'), + state: $('#posts-filter-state li.active a').data('id'), + user_id: $('#posts-filter-user li.active a').data('id'), + q: $('#posts-q').data('q'), + page: 1, }).always(function() { $('#posts-reload').removeClass('disabled') .find('.loading').toggleClass('hidden'); @@ -199,10 +209,14 @@ jQuery(function($) { reload(); }); - $('#posts').on('click', 'a.edit-user', function() { + $('#posts').on('click', 'a.edit', function() { var data = $(this).data(); - $('#user-edit-dialog').data(data).modal('show'); + if (data.edit == 'user') { + $('#user-edit-dialog').data(data).modal('show'); + } else if (data.edit == 'site') { + alert('TODO: edit site'); + } // stop event return false; diff --git a/src/guff.cr b/src/guff.cr index dc04fbe..ea9f73a 100644 --- a/src/guff.cr +++ b/src/guff.cr @@ -321,7 +321,7 @@ module Guff 'project' END) as post_type, - (CASE WHEN b.state = 'posted' THEN + (CASE WHEN b.state = 'public' THEN CASE WHEN x.post_id IS NOT NULL THEN strftime('/%%Y/%%m/%%d/', a.posted_at) || a.slug || '.html' WHEN y.post_id IS NOT NULL THEN @@ -409,7 +409,7 @@ module Guff sets << "state_id = (SELECT state_id FROM states WHERE state = ?)" args << state - if state == "posted" && !have_posted_at + if state == "public" && !have_posted_at # set posted_at by default sets << "posted_at = COALESCE(posted_at, CURRENT_TIMESTAMP)" end @@ -479,6 +479,7 @@ module Guff def get_posts( site_id : Int64? = nil, + user_id : Int64? = nil, type : String? = nil, state : String? = nil, q : String? = nil, @@ -496,6 +497,12 @@ module Guff args << site_id.to_s end + if user_id + # add user filter + filters << "a.created_by = ?" + args << user_id.to_s + end + if type # add type filter filters << case type @@ -519,7 +526,7 @@ module Guff args << state else # default state filter - filters << "b.state IN ('draft', 'posted')" + filters << "b.state IN ('draft', 'public')" end if q && q.match(/\S+/) @@ -585,7 +592,7 @@ module Guff WHERE a.site_id = ? AND b.slug = ? - AND d.state = 'posted' + AND d.state = 'public' ORDER BY b.created_at DESC LIMIT 1 @@ -717,7 +724,7 @@ module Guff WHERE a.site_id = ? AND b.slug = ? - AND d.state = 'posted' + AND d.state = 'public' ORDER BY b.created_at DESC LIMIT 1 @@ -846,7 +853,7 @@ module Guff WHERE a.site_id = ? AND %s - AND d.state = 'posted' + AND d.state = 'public' -- TODO: handle posted_at and expired_at ORDER BY COALESCE(b.posted_at, b.created_at) DESC @@ -1252,6 +1259,34 @@ module Guff end end + class StateModel < Model + SQL = { + get_states: " + SELECT state_id, + state, + name, + icon + + FROM states + + ORDER BY sort + ", + } + + def get_states + rows = [] of Hash(String, String) + + @context.dbs.ro.all(SQL[:get_states]) do |row| + rows << row.reduce({} of String => String) do |r, k, v| + r[k] = v.to_s + r + end + end + + rows + end + end + class SiteModel < Model SQL = { get_id: " @@ -1287,7 +1322,19 @@ module Guff WHERE is_active AND is_default - " + ", + + get_sites: " + SELECT site_id, + name, + is_active, + is_default + + FROM sites + + ORDER BY LOWER(name) + + ", } def get_id(host : String?) : Int64? @@ -1298,6 +1345,19 @@ module Guff def get_default_id : Int64 @context.dbs.ro.one(SQL[:get_default_id]).not_nil!.to_i64 end + + def get_sites + rows = [] of Hash(String, String) + + @context.dbs.ro.all(SQL[:get_sites]) do |row| + rows << row.reduce({} of String => String) do |r, k, v| + r[k] = v.to_s + r + end + end + + rows + end end class RoleModel < Model @@ -1338,6 +1398,7 @@ module Guff blog: Models::BlogModel, site: Models::SiteModel, role: Models::RoleModel, + state: Models::StateModel, }) end @@ -1468,7 +1529,8 @@ module Guff module PostAPI def do_post_get_posts(params : HTTP::Params) @context.models.post.get_posts( - site_id: params["site_id"]? ? params["site_id"].to_i64 : nil, + site_id: (params["site_id"]? && params["site_id"] != "all") ? params["site_id"].to_i64 : nil, + user_id: (params["user_id"]? && params["user_id"] != "all") ? params["user_id"].to_i64 : nil, state: params["state"]?, type: params["type"]?, q: params["q"]?, @@ -1640,6 +1702,12 @@ module Guff @context.models.user.get_users end end + + module SiteAPI + def do_site_get_sites(params : HTTP::Params) + @context.models.site.get_sites + end + end end module Views @@ -1835,33 +1903,37 @@ module Guff new_post_button: " <a href='#' - class='btn btn-primary add-post' - title='Create new blog post.' - data-type='blog' - > - <i class='fa fa-plus-circle'></i> - New Post - </a><!-- btn --> - - <a - href='#' class='btn btn-primary' - title='Show additonal options.' + title='Create new blog post, page, or project.' data-toggle='dropdown' > - <i class='fa fa-caret-down'></i> + <i class='fa fa-plus-circle'></i> + Create + <i class='fa fa-fw fa-caret-down'></i> </a> <ul class='dropdown-menu'> <li> <a href='#' + title='Create new blog post.' + class='add-post' + data-type='blog' + > + <i class='fa fa-fw fa-sticky-note-o'></i> + Blog Post + </a> + </li> + + <li> + <a + href='#' title='Create new page.' class='add-post' data-type='page' > <i class='fa fa-fw fa-bookmark-o'></i> - New Page + Page </a> </li> @@ -1873,7 +1945,7 @@ module Guff data-type='project' > <i class='fa fa-fw fa-cube'></i> - New Project + Project </a> </li> </ul> @@ -1882,7 +1954,7 @@ module Guff state_button: " <a href='#' - class='btn %s' + class='btn btn-default' title='Mark as %s.' data-val='%s' > @@ -1908,37 +1980,50 @@ module Guff end end - STATES = [{ - id: "draft", - name: "Draft", - icon: "fa-wrench", - css: "btn-primary", - }, { - id: "posted", - name: "Posted", - icon: "fa-bullhorn", - css: "btn-default", - }, { - id: "deleted", - name: "Deleted", - icon: "fa-trash", - css: "btn-default", - }] - private def state_buttons @state_buttons ||= String.build do |io| - STATES.each do |row| + @context.models.state.get_states.each do |row| io << TEMPLATES[:state_button] % [ - h(row[:css]), - h(row[:name]), - h(row[:id]), - h(row[:icon]), - h(row[:name]) + h(row["name"]), + h(row["state"]), + h(row["icon"]), + h(row["name"]) ] end end end + private def authors_menu_items + @context.models.user.get_users.map do |row| + { + id: row["user_id"], + name: row["name"], + text: "Show author \"%s\"." % [row["name"]], + } + end + end + + private def sites_menu_items + @context.models.site.get_sites.map do |row| + { + id: row["site_id"], + name: row["name"], + text: "Show site \"%s\"." % [row["name"]], + } + end + end + + private def states_menu_items + @context.models.state.get_states.map do |row| + { + id: row["state"], + name: row["name"], + icon: row["icon"], + text: "Show state \"%s\"." % [row["name"]], + } + end + end + ECR.def_to_s("src/views/admin-page.ecr") end @@ -2021,6 +2106,7 @@ module Guff APIs::PageAPI, APIs::ProjectAPI, APIs::BlogAPI, + APIs::SiteAPI, ] include_api_modules(API_MODULES) @@ -2613,15 +2699,22 @@ module Guff state = LOWER(state) ), + icon TEXT UNIQUE NOT NULL CHECK ( + LENGTH(state) > 0 AND + state = LOWER(state) + ), + -- user-visible state name - state_name TEXT UNIQUE NOT NULL - CHECK (LENGTH(state_name) > 0) + name TEXT UNIQUE NOT NULL + CHECK (LENGTH(name) > 0), + + sort INTEGER UNIQUE NOT NULL ) }, %{ - INSERT INTO states(state_id, state, state_name) VALUES - (1, 'draft', 'Draft'), - (2, 'posted', 'Posted'), - (3, 'deleted', 'Deleted') + INSERT INTO states(state_id, state, icon, name, sort) VALUES + (1, 'draft', 'fa-wrench', 'Draft', 1), + (2, 'public', 'fa-eye', 'Public', 2), + (3, 'deleted', 'fa-trash', 'Deleted', 3) }, %{ CREATE TABLE posts ( post_id INTEGER PRIMARY KEY, @@ -2774,7 +2867,7 @@ module Guff 1, 1, 1, - (SELECT state_id FROM states WHERE state = 'posted'), + (SELECT state_id FROM states WHERE state = 'public'), CURRENT_TIMESTAMP, 'Test Page', 'test-page', @@ -2783,7 +2876,7 @@ module Guff 2, 1, 1, - (SELECT state_id FROM states WHERE state = 'posted'), + (SELECT state_id FROM states WHERE state = 'public'), CURRENT_TIMESTAMP, 'Test Project', 'test-project', @@ -2792,7 +2885,7 @@ module Guff 3, 1, 1, - (SELECT state_id FROM states WHERE state = 'posted'), + (SELECT state_id FROM states WHERE state = 'public'), CURRENT_TIMESTAMP, 'Test Blog', 'test-blog', diff --git a/src/views/admin-page.ecr b/src/views/admin-page.ecr index f2b44f0..4e271ee 100644 --- a/src/views/admin-page.ecr +++ b/src/views/admin-page.ecr @@ -86,6 +86,7 @@ %></div><!-- btn-group --> <div class='btn-group btn-group-sm'> + <span> </span> </div><!-- btn-group --> <div class='btn-group btn-group-sm'><%= @@ -107,15 +108,18 @@ type: "divider", }, { id: "blog", - name: "Blog Posts", + name: "Blog Post", + icon: "fa-sticky-note-o", text: "Show blog posts.", }, { id: "page", - name: "Pages", + name: "Page", + icon: "fa-bookmark-o", text: "Show pages.", }, { id: "project", - name: "Projects", + name: "Project", + icon: "fa-cube", text: "Show projects.", }], ) @@ -138,19 +142,49 @@ text: "Show drafts and posted items.", }, { type: "divider", + }].concat(states_menu_items), + ) + %></div><!-- btn-group --> + + <div class='btn-group btn-group-sm'><%= + dropdown( + id: "posts-filter-site", + css: "posts-filter-menu", + + name: "Site", + text: "Filter by site.", + + icon: "", + default: "all", + + items: [{ + id: "all", + name: "All", + text: "Show all sites.", }, { - id: "draft", - name: "Draft", - text: "Show draft items.", - }, { - id: "posted", - name: "Posted", - text: "Show posted items.", + type: "divider", + }].concat(sites_menu_items), + ) + %></div><!-- btn-group --> + + <div class='btn-group btn-group-sm'><%= + dropdown( + id: "posts-filter-user", + css: "posts-filter-menu", + + name: "Author", + text: "Filter by author.", + + icon: "", + default: "all", + + items: [{ + id: "all", + name: "All", + text: "Show all authors.", }, { - id: "deleted", - name: "Deleted", - text: "Show deleted items.", - }], + type: "divider", + }].concat(authors_menu_items), ) %></div><!-- btn-group --> @@ -160,7 +194,7 @@ class='btn btn-default search-toggle' title='Toggle search field.' > - <i class='fa fa-search'></i> + <i class='fa fa-fw fa-search'></i> </a><!-- btn--> </div><!-- btn-group --> @@ -172,11 +206,11 @@ title='Reload posts' > <span class='loading'> - <i class='fa fa-refresh'></i> + <i class='fa fa-fw fa-refresh'></i> </span> <span class='loading hidden'> - <i class='fa fa-spinner fa-spin'></i> + <i class='fa fa-fw fa-spinner fa-spin'></i> </span> </a><!-- btn --> </div><!-- btn-group --> @@ -206,9 +240,9 @@ <tr class='small'> <th> </th> <th>Name</th> - <th>Author</th> <th>Site</th> <th>URL / Slug</th> + <th>Author</th> <th>Created</th> <th>Posted</th> </tr> |