diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2017-12-12 03:31:07 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2017-12-12 03:31:07 +0100 |
| commit | 942a72123ecf7ed91cf3cba1124adc11a3615208 (patch) | |
| tree | 42fa36700fd80c4903acb0ecb2b1e0bbdc8da2d6 | |
| parent | 41d0bd185c19c8a51ed9b85700f52181b6cc5012 (diff) | |
404 page and maybe deleting threads
| -rw-r--r-- | bucky/app/bucky.js | 53 | ||||
| -rw-r--r-- | bucky/app/router.js | 8 | ||||
| -rw-r--r-- | bucky/search/middleware.js | 2 | ||||
| -rw-r--r-- | bucky/util/upload.js | 4 | ||||
| -rw-r--r-- | public/assets/css/bucky.css | 23 | ||||
| -rw-r--r-- | public/assets/img/castro-the-mestizo.jpg | bin | 0 -> 32338 bytes | |||
| -rw-r--r-- | public/assets/js/lib/router.js | 7 | ||||
| -rw-r--r-- | public/assets/js/lib/views/details/index.js | 7 | ||||
| -rw-r--r-- | public/assets/js/lib/views/details/settings.js | 43 | ||||
| -rw-r--r-- | public/assets/js/util/color.js | 3 | ||||
| -rw-r--r-- | views/partials/404.ejs | 5 | ||||
| -rw-r--r-- | views/partials/footer.ejs | 2 | ||||
| -rw-r--r-- | views/partials/header.ejs | 3 | ||||
| -rw-r--r-- | views/partials/searchform.ejs | 2 | ||||
| -rw-r--r-- | views/partials/settings.ejs | 97 |
15 files changed, 192 insertions, 67 deletions
diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js index 9d8d0a7..15487e2 100644 --- a/bucky/app/bucky.js +++ b/bucky/app/bucky.js @@ -180,7 +180,38 @@ var bucky = module.exports = { res.thread.set('lastmodified', util.now()) res.thread.save().then( () => next() ) }, - + destroyThread: function (req, res, next) { + console.log(">>> destroying thread", res.thread.get('id')) + var commentPromises = res.comments.map((comment) => { + return comment.destroy() + }) + var s3client = upload.client() + var rmPromises = res.files.map((file) => { + return new Promise ((resolve, reject) => { + var thread_id = file.get('thread') + if (! thread_id || ! file.filename) { + console.log("weird malformed file?", file) + return resolve() + } + var filePath = '/bucky/' + thread_id + '/' + file.get('filename') + s3client.deleteFile(filePath, function(err, res){ + // check `err`, then do `res.pipe(..)` or `res.resume()` or whatever. + resolve() + }) + }) + }) + var filePromises = res.files.map((file) => { + return file.destroy() + }) + var threadPromise = res.thread.destroy() + var promises = [ threadPromise ].concat(commentPromises).concat(filePromises) + Promise.all(promises).then( () => { + next() + }).catch( () => { + res.sendStatus(500) + }) + }, + /* KEYWORDS */ ensureKeyword: function (req, res, next){ @@ -248,12 +279,6 @@ var bucky = module.exports = { } }) }, - checkCommentPrivacy: function(req, res, next) { - if (req.user.get('ulevel') !== 3 && req.user.get('username') !== res.comment.get('username')) { - return res.sendStatus(500) - } - next() - }, createOptionalComment: function(req, res, next){ if (! req.body.comment || ! req.body.comment.length) { return next() @@ -363,6 +388,20 @@ var bucky = module.exports = { }) }, + /* PRIVACY */ + checkThreadPrivacy: function(req, res, next) { + if (req.user.get('ulevel') !== 3 && req.user.get('username') !== res.thread.get('username')) { + return res.sendStatus(500) + } + next() + }, + checkCommentPrivacy: function(req, res, next) { + if (req.user.get('ulevel') !== 3 && req.user.get('username') !== res.comment.get('username')) { + return res.sendStatus(500) + } + next() + }, + /* MAIL */ ensureMailboxes: function (req, res, next){ diff --git a/bucky/app/router.js b/bucky/app/router.js index fc5c7ea..8eb9142 100644 --- a/bucky/app/router.js +++ b/bucky/app/router.js @@ -166,15 +166,15 @@ module.exports = function(app){ bucky.checkCommentPrivacy, bucky.destroyComment, function(req, res){ - res.send(200) + res.sendStatus(200) }) app.delete("/api/thread/:id", middleware.ensureAuthenticated, bucky.ensureThread, -// bucky.destroyThread, + bucky.checkThreadPrivacy, + bucky.destroyThread, function(req, res){ - // delete a thread - res.send(200) + res.sendStatus(200) }) app.get("/search/", diff --git a/bucky/search/middleware.js b/bucky/search/middleware.js index 32e3321..314afbc 100644 --- a/bucky/search/middleware.js +++ b/bucky/search/middleware.js @@ -94,7 +94,7 @@ module.exports = { } return m }) - res.send({ + res.json({ meta: res.search.meta, results: results, }) diff --git a/bucky/util/upload.js b/bucky/util/upload.js index 242acf0..a1810a4 100644 --- a/bucky/util/upload.js +++ b/bucky/util/upload.js @@ -22,6 +22,10 @@ module.exports.init = function (opt){ }) } +module.exports.client = function(){ + return s3 +} + module.exports.put = function (opt) { var filename var err diff --git a/public/assets/css/bucky.css b/public/assets/css/bucky.css index 2e00022..5d4a1a6 100644 --- a/public/assets/css/bucky.css +++ b/public/assets/css/bucky.css @@ -13,6 +13,10 @@ body { body.loading { opacity: 0; } +body.black { + background: #211; + color: #eee; +} * { box-sizing: border-box; } @@ -35,6 +39,7 @@ button, input[type=submit] { margin: 3px; background-color: #c8d0dc; text-transform: uppercase; + cursor: pointer; } .desktop button:hover, .desktop input[type=submit] { @@ -370,6 +375,7 @@ tr:nth-child(even) td.black { background-color: #eee; border-bottom-color: position: relative; vertical-align: top; padding-right: 110px; + color: #111111; } .comment .body { font-size: 12px; @@ -627,7 +633,7 @@ pre br { } #search .desc { display: block; - max-width: 500px; + width: 500px; padding-left: 10px; } #search .meta { @@ -677,9 +683,15 @@ pre br { background: transparent; outline: 0; width: 270px; + transition: background 200ms; + background: white; +} +.search_form input[type='text']:invalid { + background: transparent; } .search_form input[type='text']:focus { border-bottom: 1px solid #211; + border-radius: 2px 2px 0 0; color: #211; } @@ -760,6 +772,15 @@ header .search_form { display: inline-block; } +/* 404 */ +#error_404 { + display: none; + margin: 10px 0; +} +#error_404 a { + font-size: 16px; +} + @media (max-width: 700px) { body { padding: 10px 10px; diff --git a/public/assets/img/castro-the-mestizo.jpg b/public/assets/img/castro-the-mestizo.jpg Binary files differnew file mode 100644 index 0000000..dde4b21 --- /dev/null +++ b/public/assets/img/castro-the-mestizo.jpg diff --git a/public/assets/js/lib/router.js b/public/assets/js/lib/router.js index f9850e8..a83437a 100644 --- a/public/assets/js/lib/router.js +++ b/public/assets/js/lib/router.js @@ -82,4 +82,11 @@ var SiteRouter = Router.extend({ app.view.load() }, + error404: function(){ + $("content").hide() + $("#error_404").show() + $("h1").html("error: page not found") + $("body").removeClass("loading") + }, + })
\ No newline at end of file diff --git a/public/assets/js/lib/views/details/index.js b/public/assets/js/lib/views/details/index.js index 5550173..f8e9d50 100644 --- a/public/assets/js/lib/views/details/index.js +++ b/public/assets/js/lib/views/details/index.js @@ -18,7 +18,12 @@ var DetailsView = View.extend({ load: function(id){ id = id.replace(/\D/g, "") - $.get(this.action + id, this.populate.bind(this)) + $.ajax({ + method: "get", + url: this.action + id, + success: this.populate.bind(this), + error: app.router.error404, + }) }, populate: function(data){ diff --git a/public/assets/js/lib/views/details/settings.js b/public/assets/js/lib/views/details/settings.js index 6e6b0b2..eacbec4 100644 --- a/public/assets/js/lib/views/details/settings.js +++ b/public/assets/js/lib/views/details/settings.js @@ -5,7 +5,9 @@ var ThreadSettingsForm = FormView.extend({ events: { "click": "hide", "click .inner": "stopPropagation", - "click .close_link": "hide" + "click .thread_delete": "deleteThread", + "click .close_link": "hide", + "change [name=color]": "changeColor", }, action: "", @@ -28,7 +30,7 @@ var ThreadSettingsForm = FormView.extend({ var files = data.files var settings = thread.settings var display = thread.display - + this.$(".close_link").attr("href", "/details/" + thread.id) this.$(".metadata").html(metadata(thread)) this.$("[name=title]").val(sanitize(thread.title)) @@ -55,17 +57,19 @@ var ThreadSettingsForm = FormView.extend({ }) $keyword.val(thread.keyword) }.bind(this)) - console.log(thread) }, validate: function(){ var errors = [] - var comment = $("[name=comment]").val() - if (! comment || ! comment.length) { - errors.push("Please enter a comment.") + var title = $("[name=title]").val() + if (! title || ! title.length) { + errors.push("Please enter a title.") } return errors.length ? errors : null }, + + serialize: function(){ + }, success: function(data){ window.location.href = "/details/" + data.comment.thread @@ -91,5 +95,32 @@ var ThreadSettingsForm = FormView.extend({ if (this.visible) this.hide() else this.show() }, + + changeColor: function(){ + var color_name = this.$("[name=color]").val() + set_background_color(color_name) + }, + + deleteThread: function(e){ + var data = this.options.parent.data + var id = data.thread.id + var comment_count = (data.comments || []).length + var file_count = (data.files || []).length + var msg = "Are you sure you want to delete this thread?\n\n#" + id + ' "' + sanitize(data.thread.title) + '"' + msg += " + " + comment_count + " comment" + courtesy_s(comment_count) + if ( file_count) msg += " + " + file_count + " file" + courtesy_s(file_count) + var should_remove = confirm(msg) + if (should_remove) { + $.ajax({ + method: "DELETE", + url: "/api/thread/" + id, + headers: { "csrf-token": $("[name=_csrf]").attr("value") }, + data: { csrf: csrf() }, + success: function(){ + window.location.href = "/" + }, + }) + } + }, })
\ No newline at end of file diff --git a/public/assets/js/util/color.js b/public/assets/js/util/color.js index bcdfe77..6d33a72 100644 --- a/public/assets/js/util/color.js +++ b/public/assets/js/util/color.js @@ -110,12 +110,11 @@ function set_background_color_from_time(){ set_background_color(color_name) } function set_background_color(color_name){ - console.log(color_name) color_name = color_name || "plain" var color = COLORS[color_name] .clone() .mottleRGB(4,4,8) // .add(nighttime_quotient()) -console.log(color.toString()) document.body.style.backgroundColor = color.toString() + $(document.body).toggleClass("black", color_name === "black") } diff --git a/views/partials/404.ejs b/views/partials/404.ejs new file mode 100644 index 0000000..081b514 --- /dev/null +++ b/views/partials/404.ejs @@ -0,0 +1,5 @@ +<div id="error_404"> + <a href="/">← back to bucky</a> + <br><br> + <a href="/"><img src="/assets/img/castro-the-mestizo.jpg"></a> +</div>
\ No newline at end of file diff --git a/views/partials/footer.ejs b/views/partials/footer.ejs index 41d2ce3..163e28b 100644 --- a/views/partials/footer.ejs +++ b/views/partials/footer.ejs @@ -1,3 +1,5 @@ +</content> +<% include ../partials/404 %> </body> <% include ../partials/scripts %> </html>
\ No newline at end of file diff --git a/views/partials/header.ejs b/views/partials/header.ejs index d96179d..c810114 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -12,4 +12,5 @@ <header> <h1><%= title %></h1> <% include ../partials/searchform %> -</header>
\ No newline at end of file +</header> +<content>
\ No newline at end of file diff --git a/views/partials/searchform.ejs b/views/partials/searchform.ejs index 7eea248..12b7ca0 100644 --- a/views/partials/searchform.ejs +++ b/views/partials/searchform.ejs @@ -1,4 +1,4 @@ <form class="search_form" action="/search" method="get"> <div class='button'></div> - <input type="text" name="query"> + <input type="text" name="query" required> </form>
\ No newline at end of file diff --git a/views/partials/settings.ejs b/views/partials/settings.ejs index bb5d9e4..adf184e 100644 --- a/views/partials/settings.ejs +++ b/views/partials/settings.ejs @@ -2,58 +2,68 @@ <div class="inner"> <h2>thread settings</h2> <a class="close_link">exit settings</a> - <form id="thread_controls"> - <div id="thread_fields"> - <div> - <label for="thread_title">Title</label> + <div id="thread_controls"> + <div id="left_side"> + <form id="thread_fields"> <div> - <input id="thread_title" name="title" type="text"> + <label for="thread_title">Title</label> + <div> + <input id="thread_title" name="title" type="text"> + </div> </div> - </div> -<!-- - <div> - <label for="thread_bg">Background</label> + <!-- <div> - <input id="thread_bg" name="bg" type="text" placeholder="Enter URL"><br> - <img id="thread_bg_img" /> + <label for="thread_bg">Background</label> + <div> + <input id="thread_bg" name="bg" type="text" placeholder="Enter URL"><br> + <img id="thread_bg_img" /> + </div> </div> + --> + <div class="dropdown"> + <label for="thread_color">Color</label> + <select id="thread_color" name="color"></select> + </div> + <div class="dropdown"> + <label for="thread_keyword">Keyword</label> + <select id="thread_keyword" name="keyword"></select> + </div> + <div> + <label for="thread_hoots">hoot style</label> + <input id="thread_hoots" name="hoots" value="0" type="hidden"> + <input id="thread_hoots" name="hoots" value="1" type="checkbox"> + </div> + <div> + <label for="thread_shorturls">shorten urls</label> + <input id="thread_shorturls" name="shorturls" value="0" type="hidden"> + <input id="thread_shorturls" name="shorturls" value="1" type="checkbox"> + </div> + <div> + <label></label> + <input id="thread_submit" value="Save" type="submit"> + </div> + <div> + <label></label> + <div id="errors"></div> + </div> + </form> + <br><br> + <div class="thread_field"> + <label style="padding-top: 2px">danger zone:</label> + <div><button class="thread_delete">Delete This Thread</button></div> </div> ---> - <div class="dropdown"> - <label for="thread_color">Color</label> - <select id="thread_color" name="color"></select> - </div> - <div class="dropdown"> - <label for="thread_keyword">Keyword</label> - <select id="thread_keyword" name="keyword"></select> - </div> - <div> - <label for="thread_hoots">hoot style</label> - <input id="thread_hoots" name="hoots" value="0" type="hidden"> - <input id="thread_hoots" name="hoots" value="1" type="checkbox"> - </div> - <div> - <label for="thread_shorturls">shorten urls</label> - <input id="thread_shorturls" name="shorturls" value="0" type="hidden"> - <input id="thread_shorturls" name="shorturls" value="1" type="checkbox"> - </div> - <div> - <label></label> - <input id="thread_submit" value="Save" type="submit"> - </div> - </form> - + </div> </div> </div> </div> <style> #thread_settings h2 { - font-size: 20px; + font-size: 16px; margin: 0; } #thread_settings .inner { - padding: 10px; + padding: 20px; text-align: left; } #thread_controls { @@ -67,18 +77,16 @@ #thread_fields { text-align: left; } + .thread_field, #thread_fields > div { display: flex; flex-direction: row; margin-top: 5px; } - #thread_fields label { + #thread_controls label { margin-top: 4px; padding-right: 5px; } - #thread_fields .shim { - height: 10px; - } #thread_fields input[type=text] { font-size: 13px; width: 200px; @@ -86,11 +94,14 @@ } #thread_settings .close_link { position: absolute; - top: 15px; + top: 23px; right: 10px; } #thread_fields label { display: block; width: 80px; } + .desktop button.thread_delete:hover { + background: #ff8288; + } </style>
\ No newline at end of file |
