From bc8e1b05a692b8b547430cbef0f1d166a971ac1d Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Mon, 15 Sep 2014 11:38:24 +0200 Subject: [PATCH] Implemented post uploads (closed #11) --- data/.gitignore | 1 + data/config.ini | 1 + public_html/css/forms.css | 14 +- public_html/js/Auth.js | 1 + public_html/js/Controls/TagInput.js | 8 +- .../js/Presenters/PostUploadPresenter.js | 26 ++- public_html/templates/post-upload.tpl | 24 +-- src/Controllers/PostController.php | 41 ++++ src/Controllers/ViewProxies/PostViewProxy.php | 27 +++ src/Dao/AbstractDao.php | 39 +++- .../EntityConverters/PostEntityConverter.php | 24 ++- .../EntityConverters/TagEntityConverter.php | 20 ++ src/Dao/PostDao.php | 74 +++++++- src/Dao/TagDao.php | 13 ++ src/Entities/Entity.php | 40 ++++ src/Entities/Post.php | 157 ++++++++++++++++ src/Entities/Tag.php | 10 + src/FormData/UploadFormData.php | 39 ++++ src/Helpers/EnumHelper.php | 32 +++- src/Helpers/MimeHelper.php | 37 ++++ src/Privilege.php | 1 + src/Services/FileService.php | 41 +++- src/Services/PostService.php | 176 ++++++++++++++++++ .../SmartThumbnailGenerator.php | 23 +-- src/Services/ThumbnailService.php | 2 +- src/Upgrades/Upgrade03.php | 42 +++++ src/Validator.php | 24 +++ src/di.php | 2 + tests/AbstractTestCase.php | 10 + tests/Dao/PostDaoTest.php | 88 ++++++--- tests/Helpers/InputReaderTest.php | 13 ++ tests/Services/FileServiceTest.php | 14 +- tests/Services/PostServiceTest.php | 157 ++++++++++++++++ tests/ValidatorTest.php | 27 +++ tests/test_files/flash.swf | Bin 0 -> 226172 bytes tests/test_files/image.jpg | Bin 0 -> 687645 bytes tests/test_files/video.mp4 | Bin 0 -> 14667 bytes 37 files changed, 1159 insertions(+), 89 deletions(-) create mode 100644 src/Controllers/PostController.php create mode 100644 src/Controllers/ViewProxies/PostViewProxy.php create mode 100644 src/Dao/EntityConverters/TagEntityConverter.php create mode 100644 src/Dao/TagDao.php create mode 100644 src/FormData/UploadFormData.php create mode 100644 src/Helpers/MimeHelper.php create mode 100644 src/Services/PostService.php create mode 100644 src/Upgrades/Upgrade03.php create mode 100644 tests/Helpers/InputReaderTest.php create mode 100644 tests/Services/PostServiceTest.php create mode 100644 tests/test_files/flash.swf create mode 100644 tests/test_files/image.jpg create mode 100644 tests/test_files/video.mp4 diff --git a/data/.gitignore b/data/.gitignore index a64f8e06..7d3317ca 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -2,3 +2,4 @@ db.sqlite executed_upgrades.txt local.ini thumbnails +posts diff --git a/data/config.ini b/data/config.ini index 3cca980d..827f5c52 100644 --- a/data/config.ini +++ b/data/config.ini @@ -38,6 +38,7 @@ listSafePosts = anonymous, regularUser, powerUser, moderator, administ listSketchyPosts = anonymous, regularUser, powerUser, moderator, administrator listUnsafePosts = anonymous, regularUser, powerUser, moderator, administrator uploadPosts = regularUser, powerUser, moderator, administrator +uploadPostsAnonymously = regularUser, powerUser, moderator, administrator listTags = anonymous, regularUser, powerUser, moderator, administrator diff --git a/public_html/css/forms.css b/public_html/css/forms.css index 17f5ad80..f96040ef 100644 --- a/public_html/css/forms.css +++ b/public_html/css/forms.css @@ -51,19 +51,25 @@ input[type=button] { background: #eee; font-family: 'Droid Sans', sans-serif; font-size: 17px; +} +button:not(:disabled), +input[type=button]:not(:disabled) { cursor: pointer; } -button:hover, -input[type=button]:hover { +button:not(:disabled):hover, +input[type=button]:not(:disabled):hover { background: #f5f5f5; } +button:disabled { + color: gray; +} button.highlight, input[type=button].highlight { background: #ad5; } -button:hover.highlight, -input[type=button]:hover.highlight { +button:not(:disabled):hover.highlight, +input[type=button]:not(:disabled):hover.highlight { background: #dfa; } diff --git a/public_html/js/Auth.js b/public_html/js/Auth.js index fdbe202e..2ffcf07d 100644 --- a/public_html/js/Auth.js +++ b/public_html/js/Auth.js @@ -22,6 +22,7 @@ App.Auth = function(_, jQuery, util, api, appState, promise) { listSketchyPosts: 'listSketchyPosts', listUnsafePosts: 'listUnsafePosts', uploadPosts: 'uploadPosts', + uploadPostsAnonymously: 'uploadPostsAnonymously', listTags: 'listTags', }; diff --git a/public_html/js/Controls/TagInput.js b/public_html/js/Controls/TagInput.js index b794d687..3ad09284 100644 --- a/public_html/js/Controls/TagInput.js +++ b/public_html/js/Controls/TagInput.js @@ -11,6 +11,7 @@ App.Controls.TagInput = function( var KEY_RETURN = 13; var KEY_SPACE = 32; var KEY_BACKSPACE = 8; + var tagConfirmKeys = [KEY_RETURN, KEY_SPACE]; var tags = []; var options = { @@ -54,7 +55,7 @@ App.Controls.TagInput = function( }); $input.unbind('keydown').bind('keydown', function(e) { - if (e.which === KEY_RETURN || e.which === KEY_SPACE) { + if (_.contains(tagConfirmKeys, e.which)) { e.preventDefault(); var tag = $input.val(); addTag(tag); @@ -128,11 +129,16 @@ App.Controls.TagInput = function( return tags; } + function focus() { + $input.focus(); + } + _.extend(options, { setTags: setTags, getTags: getTags, removeTag: removeTag, addTag: addTag, + focus: focus, }); return options; }; diff --git a/public_html/js/Presenters/PostUploadPresenter.js b/public_html/js/Presenters/PostUploadPresenter.js index 8a12f272..deb4074d 100644 --- a/public_html/js/Presenters/PostUploadPresenter.js +++ b/public_html/js/Presenters/PostUploadPresenter.js @@ -7,6 +7,7 @@ App.Presenters.PostUploadPresenter = function( mousetrap, promise, util, + auth, api, router, topNavigationPresenter, @@ -30,7 +31,9 @@ App.Presenters.PostUploadPresenter = function( } function render() { - $el.html(template()); + $el.html(template({ + canUploadPostsAnonymously: auth.hasPrivilege(auth.privileges.uploadPostsAnonymously) + })); $messages = $el.find('.messages'); tagInput = new App.Controls.TagInput($el.find('form [name=tags]'), _, jQuery); @@ -61,10 +64,10 @@ App.Presenters.PostUploadPresenter = function( return { safety: 'safe', source: null, - fileName: null, anonymous: false, tags: [], + fileName: null, content: null, url: null, thumbnail: null, @@ -273,7 +276,9 @@ App.Presenters.PostUploadPresenter = function( hidePostEditForm(); } else { showPostEditForm(selectedPosts); + tagInput.focus(); } + $el.find('.post-table-op').prop('disabled', selectedPosts.length === 0); } function hidePostEditForm() { @@ -292,7 +297,7 @@ App.Presenters.PostUploadPresenter = function( } else { var post = selectedPosts[0]; $postEditForm.parent('.form-slider').find('.thumbnail').slideDown(); - $postEditForm.find('.file-name strong').text(post.fileName); + $postEditForm.find('.file-name strong').text(post.fileName || post.url); updatePostThumbnailInForm(post); } @@ -488,6 +493,7 @@ App.Presenters.PostUploadPresenter = function( function uploadNextPost() { messagePresenter.hideMessages($messages); + messagePresenter.showInfo($messages, 'Uploading in progress…'); var posts = getAllPosts(); if (posts.length === 0) { @@ -503,14 +509,16 @@ App.Presenters.PostUploadPresenter = function( if (post.url) { formData.url = post.url; } else { - formData.file = post.content; + formData.content = post.content; + formData.contentFileName = post.fileName; } formData.source = post.source; formData.safety = post.safety; - formData.anonymous = post.anonymous; - formData.tags = post.tags.join(', '); + formData.anonymous = (post.anonymous | 0); + formData.tags = post.tags.join(' '); if (post.tags.length === 0) { + messagePresenter.hideMessages($messages); messagePresenter.showError($messages, 'No tags set.'); interactionEnabled = true; return; @@ -519,9 +527,12 @@ App.Presenters.PostUploadPresenter = function( promise.wait(api.post('/posts', formData)).then(function(response) { $row.slideUp(function(response) { $row.remove(); + posts.shift(); + setAllPosts(posts); uploadNextPost(); }); }).fail(function(response) { + messagePresenter.hideMessages($messages); messagePresenter.showError($messages, response.json && response.json.error || response); interactionEnabled = true; }); @@ -536,7 +547,6 @@ App.Presenters.PostUploadPresenter = function( $el.find('tbody input[type=checkbox]').prop('checked', false); postTableCheckboxesChanged(); - messagePresenter.showInfo($messages, 'Uploading in progress…'); interactionEnabled = false; uploadNextPost(); @@ -549,4 +559,4 @@ App.Presenters.PostUploadPresenter = function( }; -App.DI.register('postUploadPresenter', ['_', 'jQuery', 'mousetrap', 'promise', 'util', 'api', 'router', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.PostUploadPresenter); +App.DI.register('postUploadPresenter', ['_', 'jQuery', 'mousetrap', 'promise', 'util', 'auth', 'api', 'router', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.PostUploadPresenter); diff --git a/public_html/templates/post-upload.tpl b/public_html/templates/post-upload.tpl index 5d5fbf4c..e338043a 100644 --- a/public_html/templates/post-upload.tpl +++ b/public_html/templates/post-upload.tpl @@ -47,13 +47,13 @@