mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
remove useless upload topic direct association
This commit is contained in:
parent
e603c85fa0
commit
6ea91b4416
6 changed files with 81 additions and 93 deletions
|
@ -44,15 +44,15 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
}.property('content.createdPost'),
|
}.property('content.createdPost'),
|
||||||
|
|
||||||
observeReplyChanges: function() {
|
observeReplyChanges: function() {
|
||||||
var _this = this;
|
var composerView = this;
|
||||||
if (this.get('content.hidePreview')) return;
|
if (this.get('content.hidePreview')) return;
|
||||||
Ember.run.next(null, function() {
|
Ember.run.next(null, function() {
|
||||||
var $wmdPreview, caretPosition;
|
var $wmdPreview, caretPosition;
|
||||||
if (_this.editor) {
|
if (composerView.editor) {
|
||||||
_this.editor.refreshPreview();
|
composerView.editor.refreshPreview();
|
||||||
// if the caret is on the last line ensure preview scrolled to bottom
|
// if the caret is on the last line ensure preview scrolled to bottom
|
||||||
caretPosition = Discourse.Utilities.caretPosition(_this.wmdInput[0]);
|
caretPosition = Discourse.Utilities.caretPosition(composerView.wmdInput[0]);
|
||||||
if (!_this.wmdInput.val().substring(caretPosition).match(/\n/)) {
|
if (!composerView.wmdInput.val().substring(caretPosition).match(/\n/)) {
|
||||||
$wmdPreview = $('#wmd-preview');
|
$wmdPreview = $('#wmd-preview');
|
||||||
if ($wmdPreview.is(':visible')) {
|
if ($wmdPreview.is(':visible')) {
|
||||||
return $wmdPreview.scrollTop($wmdPreview[0].scrollHeight);
|
return $wmdPreview.scrollTop($wmdPreview[0].scrollHeight);
|
||||||
|
@ -164,53 +164,50 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
initEditor: function() {
|
initEditor: function() {
|
||||||
// not quite right, need a callback to pass in, meaning this gets called once,
|
// not quite right, need a callback to pass in, meaning this gets called once,
|
||||||
// but if you start replying to another topic it will get the avatars wrong
|
// but if you start replying to another topic it will get the avatars wrong
|
||||||
var $uploadTarget, $wmdInput, editor, saveDraft, selected, template, topic, transformTemplate,
|
var $wmdInput, editor, composerView = this;
|
||||||
_this = this;
|
|
||||||
this.wmdInput = $wmdInput = $('#wmd-input');
|
this.wmdInput = $wmdInput = $('#wmd-input');
|
||||||
if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return;
|
if ($wmdInput.length === 0 || $wmdInput.data('init') === true) return;
|
||||||
|
|
||||||
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
|
$LAB.script(assetPath('defer/html-sanitizer-bundle'));
|
||||||
Discourse.ComposerView.trigger("initWmdEditor");
|
Discourse.ComposerView.trigger("initWmdEditor");
|
||||||
template = Discourse.UserSelector.templateFunction();
|
var template = Discourse.UserSelector.templateFunction();
|
||||||
|
|
||||||
transformTemplate = Handlebars.compile("{{avatar this imageSize=\"tiny\"}} {{this.username}}");
|
|
||||||
$wmdInput.data('init', true);
|
$wmdInput.data('init', true);
|
||||||
$wmdInput.autocomplete({
|
$wmdInput.autocomplete({
|
||||||
template: template,
|
template: template,
|
||||||
dataSource: function(term) {
|
dataSource: function(term) {
|
||||||
return Discourse.UserSearch.search({
|
return Discourse.UserSearch.search({
|
||||||
term: term,
|
term: term,
|
||||||
topicId: _this.get('controller.controllers.topic.content.id')
|
topicId: composerView.get('controller.controllers.topic.content.id')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
key: "@",
|
key: "@",
|
||||||
transformComplete: function(v) { return v.username; }
|
transformComplete: function(v) { return v.username; }
|
||||||
});
|
});
|
||||||
|
|
||||||
topic = this.get('topic');
|
|
||||||
this.editor = editor = Discourse.Markdown.createEditor({
|
this.editor = editor = Discourse.Markdown.createEditor({
|
||||||
lookupAvatar: function(username) {
|
lookupAvatar: function(username) {
|
||||||
return Discourse.Utilities.avatarImg({ username: username, size: 'tiny' });
|
return Discourse.Utilities.avatarImg({ username: username, size: 'tiny' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$uploadTarget = $('#reply-control');
|
var $uploadTarget = $('#reply-control');
|
||||||
this.editor.hooks.insertImageDialog = function(callback) {
|
this.editor.hooks.insertImageDialog = function(callback) {
|
||||||
callback(null);
|
callback(null);
|
||||||
_this.get('controller').send('showImageSelector', _this);
|
composerView.get('controller').send('showImageSelector', composerView);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.editor.hooks.onPreviewRefresh = function() {
|
this.editor.hooks.onPreviewRefresh = function() {
|
||||||
return _this.afterRender();
|
return composerView.afterRender();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.editor.run();
|
this.editor.run();
|
||||||
this.set('editor', this.editor);
|
this.set('editor', this.editor);
|
||||||
this.loadingChanged();
|
this.loadingChanged();
|
||||||
|
|
||||||
saveDraft = Discourse.debounce((function() {
|
var saveDraft = Discourse.debounce((function() {
|
||||||
return _this.get('controller').saveDraft();
|
return composerView.get('controller').saveDraft();
|
||||||
}), 2000);
|
}), 2000);
|
||||||
|
|
||||||
$wmdInput.keyup(function() {
|
$wmdInput.keyup(function() {
|
||||||
|
@ -223,7 +220,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
$replyTitle.keyup(function() {
|
$replyTitle.keyup(function() {
|
||||||
saveDraft();
|
saveDraft();
|
||||||
// removes the red background once the requirements are met
|
// removes the red background once the requirements are met
|
||||||
if (_this.get('controller.content.missingTitleCharacters') <= 0) {
|
if (composerView.get('controller.content.missingTitleCharacters') <= 0) {
|
||||||
$replyTitle.removeClass("requirements-not-met");
|
$replyTitle.removeClass("requirements-not-met");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -232,7 +229,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
// when the title field loses the focus...
|
// when the title field loses the focus...
|
||||||
$replyTitle.blur(function(){
|
$replyTitle.blur(function(){
|
||||||
// ...and the requirements are not met (ie. the minimum number of characters)
|
// ...and the requirements are not met (ie. the minimum number of characters)
|
||||||
if (_this.get('controller.content.missingTitleCharacters') > 0) {
|
if (composerView.get('controller.content.missingTitleCharacters') > 0) {
|
||||||
// then, "redify" the background
|
// then, "redify" the background
|
||||||
$replyTitle.toggleClass("requirements-not-met", true);
|
$replyTitle.toggleClass("requirements-not-met", true);
|
||||||
}
|
}
|
||||||
|
@ -245,22 +242,21 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
$uploadTarget.fileupload({
|
$uploadTarget.fileupload({
|
||||||
url: Discourse.getURL('/uploads'),
|
url: Discourse.getURL('/uploads'),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
timeout: 20000,
|
timeout: 20000
|
||||||
formData: { topic_id: 1234 }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// submit - this event is triggered for each upload
|
// submit - this event is triggered for each upload
|
||||||
$uploadTarget.on('fileuploadsubmit', function (e, data) {
|
$uploadTarget.on('fileuploadsubmit', function (e, data) {
|
||||||
var result = Discourse.Utilities.validateFilesForUpload(data.files);
|
var result = Discourse.Utilities.validateFilesForUpload(data.files);
|
||||||
// reset upload status when everything is ok
|
// reset upload status when everything is ok
|
||||||
if (result) _this.setProperties({ uploadProgress: 0, loadingImage: true });
|
if (result) composerView.setProperties({ uploadProgress: 0, loadingImage: true });
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
// send - this event is triggered when the upload request is about to start
|
// send - this event is triggered when the upload request is about to start
|
||||||
$uploadTarget.on('fileuploadsend', function (e, data) {
|
$uploadTarget.on('fileuploadsend', function (e, data) {
|
||||||
// hide the "image selector" modal
|
// hide the "image selector" modal
|
||||||
_this.get('controller').send('closeModal');
|
composerView.get('controller').send('closeModal');
|
||||||
// cf. https://github.com/blueimp/jQuery-File-Upload/wiki/API#how-to-cancel-an-upload
|
// cf. https://github.com/blueimp/jQuery-File-Upload/wiki/API#how-to-cancel-an-upload
|
||||||
var jqXHR = data.xhr();
|
var jqXHR = data.xhr();
|
||||||
// need to wait for the link to show up in the DOM
|
// need to wait for the link to show up in the DOM
|
||||||
|
@ -279,21 +275,21 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
// progress all
|
// progress all
|
||||||
$uploadTarget.on('fileuploadprogressall', function (e, data) {
|
$uploadTarget.on('fileuploadprogressall', function (e, data) {
|
||||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||||
_this.set('uploadProgress', progress);
|
composerView.set('uploadProgress', progress);
|
||||||
});
|
});
|
||||||
|
|
||||||
// done
|
// done
|
||||||
$uploadTarget.on('fileuploaddone', function (e, data) {
|
$uploadTarget.on('fileuploaddone', function (e, data) {
|
||||||
var upload = data.result;
|
var upload = data.result;
|
||||||
var html = "<img src=\"" + upload.url + "\" width=\"" + upload.width + "\" height=\"" + upload.height + "\">";
|
var html = "<img src=\"" + upload.url + "\" width=\"" + upload.width + "\" height=\"" + upload.height + "\">";
|
||||||
_this.addMarkdown(html);
|
composerView.addMarkdown(html);
|
||||||
_this.set('loadingImage', false);
|
composerView.set('loadingImage', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// fail
|
// fail
|
||||||
$uploadTarget.on('fileuploadfail', function (e, data) {
|
$uploadTarget.on('fileuploadfail', function (e, data) {
|
||||||
// hide upload status
|
// hide upload status
|
||||||
_this.set('loadingImage', false);
|
composerView.set('loadingImage', false);
|
||||||
// deal with meaningful errors first
|
// deal with meaningful errors first
|
||||||
if (data.jqXHR) {
|
if (data.jqXHR) {
|
||||||
switch (data.jqXHR.status) {
|
switch (data.jqXHR.status) {
|
||||||
|
@ -321,7 +317,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
// to finish.
|
// to finish.
|
||||||
return Em.run.later(jQuery, (function() {
|
return Em.run.later(jQuery, (function() {
|
||||||
var replyTitle = $('#reply-title');
|
var replyTitle = $('#reply-title');
|
||||||
_this.resize();
|
composerView.resize();
|
||||||
if (replyTitle.length) {
|
if (replyTitle.length) {
|
||||||
return replyTitle.putCursorAtEnd();
|
return replyTitle.putCursorAtEnd();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,16 +2,15 @@ class UploadsController < ApplicationController
|
||||||
before_filter :ensure_logged_in
|
before_filter :ensure_logged_in
|
||||||
|
|
||||||
def create
|
def create
|
||||||
params.require(:topic_id)
|
|
||||||
file = params[:file] || params[:files].first
|
file = params[:file] || params[:files].first
|
||||||
|
|
||||||
# only supports images for now
|
# only supports images for now
|
||||||
return render status: 415, json: failed_json unless file.content_type =~ /^image\/.+/
|
return render status: 415, json: failed_json unless file.content_type =~ /^image\/.+/
|
||||||
|
|
||||||
upload = Upload.create_for(current_user.id, file, params[:topic_id])
|
upload = Upload.create_for(current_user.id, file)
|
||||||
|
|
||||||
render_serialized(upload, UploadSerializer, root: false)
|
render_serialized(upload, UploadSerializer, root: false)
|
||||||
|
|
||||||
rescue FastImage::ImageFetchFailure
|
rescue FastImage::ImageFetchFailure
|
||||||
render status: 422, text: I18n.t("upload.image.fetch_failure")
|
render status: 422, text: I18n.t("upload.image.fetch_failure")
|
||||||
rescue FastImage::UnknownImageType
|
rescue FastImage::UnknownImageType
|
||||||
|
|
|
@ -5,7 +5,6 @@ require 'local_store'
|
||||||
|
|
||||||
class Upload < ActiveRecord::Base
|
class Upload < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :topic
|
|
||||||
|
|
||||||
has_many :post_uploads
|
has_many :post_uploads
|
||||||
has_many :posts, through: :post_uploads
|
has_many :posts, through: :post_uploads
|
||||||
|
@ -13,7 +12,7 @@ class Upload < ActiveRecord::Base
|
||||||
validates_presence_of :filesize
|
validates_presence_of :filesize
|
||||||
validates_presence_of :original_filename
|
validates_presence_of :original_filename
|
||||||
|
|
||||||
def self.create_for(user_id, file, topic_id)
|
def self.create_for(user_id, file)
|
||||||
# retrieve image info
|
# retrieve image info
|
||||||
image_info = FastImage.new(file.tempfile, raise_on_failure: true)
|
image_info = FastImage.new(file.tempfile, raise_on_failure: true)
|
||||||
# compute image aspect ratio
|
# compute image aspect ratio
|
||||||
|
@ -21,7 +20,6 @@ class Upload < ActiveRecord::Base
|
||||||
|
|
||||||
upload = Upload.create!({
|
upload = Upload.create!({
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
topic_id: topic_id,
|
|
||||||
original_filename: file.original_filename,
|
original_filename: file.original_filename,
|
||||||
filesize: File.size(file.tempfile),
|
filesize: File.size(file.tempfile),
|
||||||
width: width,
|
width: width,
|
||||||
|
@ -53,7 +51,6 @@ end
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
# user_id :integer not null
|
# user_id :integer not null
|
||||||
# topic_id :integer not null
|
|
||||||
# original_filename :string(255) not null
|
# original_filename :string(255) not null
|
||||||
# filesize :integer not null
|
# filesize :integer not null
|
||||||
# width :integer
|
# width :integer
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class RemoveTopicIdFromUploads < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
remove_column :uploads, :topic_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
add_column :uploads, :topic_id, :interger, null: false, default: -1
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,64 +14,54 @@ describe UploadsController do
|
||||||
|
|
||||||
context '.create' do
|
context '.create' do
|
||||||
|
|
||||||
context 'missing params' do
|
let(:logo) do
|
||||||
it 'raises an error without the topic_id param' do
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
-> { xhr :post, :create }.should raise_error(ActionController::ParameterMissing)
|
filename: 'logo.png',
|
||||||
|
type: 'image/png',
|
||||||
|
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo.png")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:logo_dev) do
|
||||||
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
|
filename: 'logo-dev.png',
|
||||||
|
type: 'image/png',
|
||||||
|
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo-dev.png")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:text_file) do
|
||||||
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
|
filename: 'LICENSE.txt',
|
||||||
|
type: 'text/plain',
|
||||||
|
tempfile: File.new("#{Rails.root}/LICENSE.txt")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:files) { [ logo_dev, logo ] }
|
||||||
|
|
||||||
|
context 'with a file' do
|
||||||
|
it 'is succesful' do
|
||||||
|
xhr :post, :create, file: logo
|
||||||
|
response.should be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'supports only images' do
|
||||||
|
xhr :post, :create, file: text_file
|
||||||
|
response.status.should eq 415
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'correct params' do
|
context 'with some files' do
|
||||||
|
|
||||||
let(:logo) do
|
it 'is succesful' do
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
xhr :post, :create, files: files
|
||||||
filename: 'logo.png',
|
response.should be_success
|
||||||
type: 'image/png',
|
|
||||||
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo.png")
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:logo_dev) do
|
it 'takes the first file' do
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
xhr :post, :create, files: files
|
||||||
filename: 'logo-dev.png',
|
response.body.should match /logo-dev.png/
|
||||||
type: 'image/png',
|
|
||||||
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo-dev.png")
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:text_file) do
|
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
|
||||||
filename: 'LICENSE.txt',
|
|
||||||
type: 'text/plain',
|
|
||||||
tempfile: File.new("#{Rails.root}/LICENSE.txt")
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:files) { [ logo_dev, logo ] }
|
|
||||||
|
|
||||||
context 'with a file' do
|
|
||||||
it 'is succesful' do
|
|
||||||
xhr :post, :create, topic_id: 1234, file: logo
|
|
||||||
response.should be_success
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'supports only images' do
|
|
||||||
xhr :post, :create, topic_id: 1234, file: text_file
|
|
||||||
response.status.should eq 415
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with some files' do
|
|
||||||
|
|
||||||
it 'is succesful' do
|
|
||||||
xhr :post, :create, topic_id: 1234, files: files
|
|
||||||
response.should be_success
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'takes the first file' do
|
|
||||||
xhr :post, :create, topic_id: 1234, files: files
|
|
||||||
response.body.should match /logo-dev.png/
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,6 @@ require 'spec_helper'
|
||||||
describe Upload do
|
describe Upload do
|
||||||
|
|
||||||
it { should belong_to :user }
|
it { should belong_to :user }
|
||||||
it { should belong_to :topic }
|
|
||||||
|
|
||||||
it { should have_many :post_uploads }
|
it { should have_many :post_uploads }
|
||||||
it { should have_many :posts }
|
it { should have_many :posts }
|
||||||
|
@ -14,7 +13,6 @@ describe Upload do
|
||||||
context '.create_for' do
|
context '.create_for' do
|
||||||
|
|
||||||
let(:user_id) { 1 }
|
let(:user_id) { 1 }
|
||||||
let(:topic_id) { 42 }
|
|
||||||
|
|
||||||
let(:logo) do
|
let(:logo) do
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
|
@ -24,14 +22,13 @@ describe Upload do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:upload) { Upload.create_for(user_id, logo, topic_id) }
|
let(:upload) { Upload.create_for(user_id, logo) }
|
||||||
|
|
||||||
let(:url) { "http://domain.com" }
|
let(:url) { "http://domain.com" }
|
||||||
|
|
||||||
shared_examples_for "upload" do
|
shared_examples_for "upload" do
|
||||||
it "is valid" do
|
it "is valid" do
|
||||||
upload.user_id.should == user_id
|
upload.user_id.should == user_id
|
||||||
upload.topic_id.should == topic_id
|
|
||||||
upload.original_filename.should == logo.original_filename
|
upload.original_filename.should == logo.original_filename
|
||||||
upload.filesize.should == File.size(logo.tempfile)
|
upload.filesize.should == File.size(logo.tempfile)
|
||||||
upload.width.should == 244
|
upload.width.should == 244
|
||||||
|
|
Loading…
Reference in a new issue