mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-12-18 03:25:31 -05:00
Interface is wired up for Approving/Rejecting posts
This commit is contained in:
parent
96d2c5069b
commit
0c233e4e25
20 changed files with 273 additions and 90 deletions
|
@ -6,6 +6,16 @@ export function Result(payload, responseJson) {
|
||||||
this.target = null;
|
this.target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ajax = Discourse.ajax;
|
||||||
|
|
||||||
|
// We use this to make sure 404s are caught
|
||||||
|
function rethrow(error) {
|
||||||
|
if (error.status === 404) {
|
||||||
|
throw "404: " + error.responseText;
|
||||||
|
}
|
||||||
|
throw(error);
|
||||||
|
}
|
||||||
|
|
||||||
export default Ember.Object.extend({
|
export default Ember.Object.extend({
|
||||||
pathFor(store, type, findArgs) {
|
pathFor(store, type, findArgs) {
|
||||||
let path = "/" + Ember.String.underscore(store.pluralize(type));
|
let path = "/" + Ember.String.underscore(store.pluralize(type));
|
||||||
|
@ -31,17 +41,18 @@ export default Ember.Object.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
findAll(store, type) {
|
findAll(store, type) {
|
||||||
return Discourse.ajax(this.pathFor(store, type));
|
return ajax(this.pathFor(store, type)).catch(rethrow);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
find(store, type, findArgs) {
|
find(store, type, findArgs) {
|
||||||
return Discourse.ajax(this.pathFor(store, type, findArgs));
|
return ajax(this.pathFor(store, type, findArgs)).catch(rethrow);
|
||||||
},
|
},
|
||||||
|
|
||||||
update(store, type, id, attrs) {
|
update(store, type, id, attrs) {
|
||||||
const data = {};
|
const data = {};
|
||||||
data[Ember.String.underscore(type)] = attrs;
|
data[Ember.String.underscore(type)] = attrs;
|
||||||
return Discourse.ajax(this.pathFor(store, type, id), { method: 'PUT', data }).then(function(json) {
|
return ajax(this.pathFor(store, type, id), { method: 'PUT', data }).then(function(json) {
|
||||||
return new Result(json[type], json);
|
return new Result(json[type], json);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -50,13 +61,13 @@ export default Ember.Object.extend({
|
||||||
const data = {};
|
const data = {};
|
||||||
const typeField = Ember.String.underscore(type);
|
const typeField = Ember.String.underscore(type);
|
||||||
data[typeField] = attrs;
|
data[typeField] = attrs;
|
||||||
return Discourse.ajax(this.pathFor(store, type), { method: 'POST', data }).then(function (json) {
|
return ajax(this.pathFor(store, type), { method: 'POST', data }).then(function (json) {
|
||||||
return new Result(json[typeField], json);
|
return new Result(json[typeField], json);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyRecord(store, type, record) {
|
destroyRecord(store, type, record) {
|
||||||
return Discourse.ajax(this.pathFor(store, type, record.get('id')), { method: 'DELETE' });
|
return ajax(this.pathFor(store, type, record.get('id')), { method: 'DELETE' });
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
|
||||||
|
function updateState(state) {
|
||||||
|
return function(post) {
|
||||||
|
post.update({ state }).then(() => {
|
||||||
|
this.get('model').removeObject(post);
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
approve(post) {
|
approve: updateState('approved'),
|
||||||
post.update({ state: 'approved' }).then(() => {
|
reject: updateState('rejected')
|
||||||
this.get('model').removeObject(post);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
reject(post) {
|
|
||||||
post.update({ state: 'rejected' }).then(() => {
|
|
||||||
this.get('model').removeObject(post);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export function throwAjaxError(undoCallback) {
|
function extractError(error) {
|
||||||
return function(error) {
|
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
Ember.Logger.error(error.stack);
|
Ember.Logger.error(error.stack);
|
||||||
}
|
}
|
||||||
|
@ -8,9 +7,6 @@ export function throwAjaxError(undoCallback) {
|
||||||
Ember.Logger.error(error);
|
Ember.Logger.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we provided an `undo` callback
|
|
||||||
if (undoCallback) { undoCallback(error); }
|
|
||||||
|
|
||||||
let parsedError;
|
let parsedError;
|
||||||
if (error.responseText) {
|
if (error.responseText) {
|
||||||
try {
|
try {
|
||||||
|
@ -25,6 +21,18 @@ export function throwAjaxError(undoCallback) {
|
||||||
Ember.Logger.error(ex.stack);
|
Ember.Logger.error(ex.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw parsedError || I18n.t('generic_error');
|
return parsedError || I18n.t('generic_error');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function throwAjaxError(undoCallback) {
|
||||||
|
return function(error) {
|
||||||
|
// If we provided an `undo` callback
|
||||||
|
if (undoCallback) { undoCallback(error); }
|
||||||
|
|
||||||
|
throw extractError(error);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function popupAjaxError(err) {
|
||||||
|
bootbox.alert(extractError(err));
|
||||||
|
}
|
||||||
|
|
|
@ -3,24 +3,30 @@ import Presence from 'discourse/mixins/presence';
|
||||||
const RestModel = Ember.Object.extend(Presence, {
|
const RestModel = Ember.Object.extend(Presence, {
|
||||||
isNew: Ember.computed.equal('__state', 'new'),
|
isNew: Ember.computed.equal('__state', 'new'),
|
||||||
isCreated: Ember.computed.equal('__state', 'created'),
|
isCreated: Ember.computed.equal('__state', 'created'),
|
||||||
|
isSaving: false,
|
||||||
|
|
||||||
afterUpdate: Ember.K,
|
afterUpdate: Ember.K,
|
||||||
|
|
||||||
update(props) {
|
update(props) {
|
||||||
|
if (this.get('isSaving')) { return Ember.RSVP.reject(); }
|
||||||
|
|
||||||
props = props || this.updateProperties();
|
props = props || this.updateProperties();
|
||||||
|
|
||||||
const type = this.get('__type'),
|
const type = this.get('__type'),
|
||||||
store = this.get('store');
|
store = this.get('store');
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.set('isSaving', true);
|
||||||
return store.update(type, this.get('id'), props).then(function(res) {
|
return store.update(type, this.get('id'), props).then(function(res) {
|
||||||
self.setProperties(self.__munge(res.payload || res.responseJson));
|
self.setProperties(self.__munge(res.payload || res.responseJson));
|
||||||
self.afterUpdate(res);
|
self.afterUpdate(res);
|
||||||
return res;
|
return res;
|
||||||
});
|
}).finally(() => this.set('isSaving', false));
|
||||||
},
|
},
|
||||||
|
|
||||||
_saveNew(props) {
|
_saveNew(props) {
|
||||||
|
if (this.get('isSaving')) { return Ember.RSVP.reject(); }
|
||||||
|
|
||||||
props = props || this.createProperties();
|
props = props || this.createProperties();
|
||||||
|
|
||||||
const type = this.get('__type'),
|
const type = this.get('__type'),
|
||||||
|
@ -28,6 +34,7 @@ const RestModel = Ember.Object.extend(Presence, {
|
||||||
adapter = store.adapterFor(type);
|
adapter = store.adapterFor(type);
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
self.set('isSaving', true);
|
||||||
return adapter.createRecord(store, type, props).then(function(res) {
|
return adapter.createRecord(store, type, props).then(function(res) {
|
||||||
if (!res) { throw "Received no data back from createRecord"; }
|
if (!res) { throw "Received no data back from createRecord"; }
|
||||||
|
|
||||||
|
@ -40,7 +47,7 @@ const RestModel = Ember.Object.extend(Presence, {
|
||||||
|
|
||||||
res.target = self;
|
res.target = self;
|
||||||
return res;
|
return res;
|
||||||
});
|
}).finally(() => this.set('isSaving', false));
|
||||||
},
|
},
|
||||||
|
|
||||||
createProperties() {
|
createProperties() {
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default Ember.Object.extend({
|
||||||
if (typeof findArgs === "object") {
|
if (typeof findArgs === "object") {
|
||||||
return self._resultSet(type, result);
|
return self._resultSet(type, result);
|
||||||
} else {
|
} else {
|
||||||
return self._hydrate(type, result[Ember.String.underscore(type)]);
|
return self._hydrate(type, result[Ember.String.underscore(type)], result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,7 @@ export default Ember.Object.extend({
|
||||||
const typeName = Ember.String.underscore(self.pluralize(type)),
|
const typeName = Ember.String.underscore(self.pluralize(type)),
|
||||||
totalRows = result["total_rows_" + typeName] || result.get('totalRows'),
|
totalRows = result["total_rows_" + typeName] || result.get('totalRows'),
|
||||||
loadMoreUrl = result["load_more_" + typeName],
|
loadMoreUrl = result["load_more_" + typeName],
|
||||||
content = result[typeName].map(obj => self._hydrate(type, obj));
|
content = result[typeName].map(obj => self._hydrate(type, obj, result));
|
||||||
|
|
||||||
resultSet.setProperties({ totalRows, loadMoreUrl });
|
resultSet.setProperties({ totalRows, loadMoreUrl });
|
||||||
resultSet.get('content').pushObjects(content);
|
resultSet.get('content').pushObjects(content);
|
||||||
|
@ -86,7 +86,7 @@ export default Ember.Object.extend({
|
||||||
|
|
||||||
_resultSet(type, result) {
|
_resultSet(type, result) {
|
||||||
const typeName = Ember.String.underscore(this.pluralize(type)),
|
const typeName = Ember.String.underscore(this.pluralize(type)),
|
||||||
content = result[typeName].map(obj => this._hydrate(type, obj)),
|
content = result[typeName].map(obj => this._hydrate(type, obj, result)),
|
||||||
totalRows = result["total_rows_" + typeName] || content.length,
|
totalRows = result["total_rows_" + typeName] || content.length,
|
||||||
loadMoreUrl = result["load_more_" + typeName];
|
loadMoreUrl = result["load_more_" + typeName];
|
||||||
|
|
||||||
|
@ -111,10 +111,39 @@ export default Ember.Object.extend({
|
||||||
return this.container.lookup('adapter:' + type) || this.container.lookup('adapter:rest');
|
return this.container.lookup('adapter:' + type) || this.container.lookup('adapter:rest');
|
||||||
},
|
},
|
||||||
|
|
||||||
_hydrate(type, obj) {
|
_hydrateEmbedded(obj, root) {
|
||||||
|
const self = this;
|
||||||
|
Object.keys(obj).forEach(function(k) {
|
||||||
|
const m = /(.+)\_id$/.exec(k);
|
||||||
|
if (m) {
|
||||||
|
const subType = m[1];
|
||||||
|
const collection = root[self.pluralize(subType)];
|
||||||
|
if (collection) {
|
||||||
|
const found = collection.findProperty('id', obj[k]);
|
||||||
|
if (found) {
|
||||||
|
const hydrated = self._hydrate(subType, found, root);
|
||||||
|
if (hydrated) {
|
||||||
|
obj[subType] = hydrated;
|
||||||
|
delete obj[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_hydrate(type, obj, root) {
|
||||||
if (!obj) { throw "Can't hydrate " + type + " of `null`"; }
|
if (!obj) { throw "Can't hydrate " + type + " of `null`"; }
|
||||||
if (!obj.id) { throw "Can't hydrate " + type + " without an `id`"; }
|
if (!obj.id) { throw "Can't hydrate " + type + " without an `id`"; }
|
||||||
|
|
||||||
|
root = root || obj;
|
||||||
|
|
||||||
|
// Experimental: If serialized with a certain option we'll wire up embedded objects
|
||||||
|
// automatically.
|
||||||
|
if (root.__rest_serializer === "1") {
|
||||||
|
this._hydrateEmbedded(obj, root);
|
||||||
|
}
|
||||||
|
|
||||||
_identityMap[type] = _identityMap[type] || {};
|
_identityMap[type] = _identityMap[type] || {};
|
||||||
|
|
||||||
const existing = _identityMap[type][obj.id];
|
const existing = _identityMap[type][obj.id];
|
||||||
|
|
|
@ -5,4 +5,3 @@ export default DiscourseRoute.extend({
|
||||||
return this.store.find('queuedPost', {status: 'new'});
|
return this.store.find('queuedPost', {status: 'new'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// This route is used for retrieving a topic based on params
|
// This route is used for retrieving a topic based on params
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
|
|
||||||
|
// Avoid default model hook
|
||||||
|
model: function() { return; },
|
||||||
|
|
||||||
setupController: function(controller, params) {
|
setupController: function(controller, params) {
|
||||||
params = params || {};
|
params = params || {};
|
||||||
params.track_visit = true;
|
params.track_visit = true;
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
<div class='queued-posts'>
|
<div class='queued-posts'>
|
||||||
{{#each post in model}}
|
{{#each post in model}}
|
||||||
<div class='queued-post'>
|
<div class='queued-post'>
|
||||||
{{#if post.title}}
|
|
||||||
<h4 class='title'>{{post.title}}</h4>
|
|
||||||
{{/if}}
|
|
||||||
<div class='poster'>
|
<div class='poster'>
|
||||||
{{avatar post.user imageSize="large"}}
|
{{avatar post.user imageSize="large"}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,11 +11,30 @@
|
||||||
</div>
|
</div>
|
||||||
<div class='clearfix'></div>
|
<div class='clearfix'></div>
|
||||||
|
|
||||||
|
<span class='post-title'>
|
||||||
|
{{i18n "queue.topic"}}
|
||||||
|
{{#if post.topic}}
|
||||||
|
{{topic-link post.topic}}
|
||||||
|
{{else}}
|
||||||
|
{{post.post_options.title}}
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
|
||||||
{{{cook-text post.raw}}}
|
{{{cook-text post.raw}}}
|
||||||
|
|
||||||
<div class='queue-controls'>
|
<div class='queue-controls'>
|
||||||
{{d-button action="approve" actionParam=post label="queue.approve" icon="check" class="btn-primary approve"}}
|
{{d-button action="approve"
|
||||||
{{d-button action="reject" actionParam=post label="queue.reject" icon="times" class="btn-warning reject"}}
|
actionParam=post
|
||||||
|
disabled=post.isSaving
|
||||||
|
label="queue.approve"
|
||||||
|
icon="check"
|
||||||
|
class="btn-primary approve"}}
|
||||||
|
{{d-button action="reject"
|
||||||
|
actionParam=post
|
||||||
|
disabled=post.isSaving
|
||||||
|
label="queue.reject"
|
||||||
|
icon="times"
|
||||||
|
class="btn-warning reject"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='clearfix'></div>
|
<div class='clearfix'></div>
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
width: $topic-body-width;
|
width: $topic-body-width;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
h4.title {
|
|
||||||
margin-bottom: 1em;
|
.post-title {
|
||||||
|
color: darken(scale-color-diff(), 50%);
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
border-bottom: 1px solid darken(scale-color-diff(), 10%);
|
border-bottom: 1px solid darken(scale-color-diff(), 10%);
|
||||||
|
|
|
@ -219,6 +219,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
def render_json_dump(obj, opts=nil)
|
def render_json_dump(obj, opts=nil)
|
||||||
opts ||= {}
|
opts ||= {}
|
||||||
|
obj['__rest_serializer'] = "1" if opts[:rest_serializer]
|
||||||
render json: MultiJson.dump(obj), status: opts[:status] || 200
|
render json: MultiJson.dump(obj), status: opts[:status] || 200
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,20 @@ class QueuedPostsController < ApplicationController
|
||||||
state = QueuedPost.states[(params[:state] || 'new').to_sym]
|
state = QueuedPost.states[(params[:state] || 'new').to_sym]
|
||||||
state ||= QueuedPost.states[:new]
|
state ||= QueuedPost.states[:new]
|
||||||
|
|
||||||
@queued_posts = QueuedPost.where(state: state)
|
@queued_posts = QueuedPost.where(state: state).includes(:topic, :user)
|
||||||
render_serialized(@queued_posts, QueuedPostSerializer, root: :queued_posts)
|
render_serialized(@queued_posts, QueuedPostSerializer, root: :queued_posts, rest_serializer: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
qp = QueuedPost.where(id: params[:id]).first
|
qp = QueuedPost.where(id: params[:id]).first
|
||||||
|
|
||||||
|
state = params[:queued_post][:state]
|
||||||
|
if state == 'approved'
|
||||||
|
qp.approve!(current_user)
|
||||||
|
elsif state == 'rejected'
|
||||||
|
qp.reject!(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
render_serialized(qp, QueuedPostSerializer, root: :queued_posts)
|
render_serialized(qp, QueuedPostSerializer, root: :queued_posts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class QueuedPostSerializer < ApplicationSerializer
|
class QueuedPostSerializer < ApplicationSerializer
|
||||||
|
|
||||||
attributes :id,
|
attributes :id,
|
||||||
:queue,
|
:queue,
|
||||||
:user_id,
|
:user_id,
|
||||||
|
@ -11,4 +12,6 @@ class QueuedPostSerializer < ApplicationSerializer
|
||||||
:created_at
|
:created_at
|
||||||
|
|
||||||
has_one :user, serializer: BasicUserSerializer, embed: :object
|
has_one :user, serializer: BasicUserSerializer, embed: :object
|
||||||
|
has_one :topic, serializer: BasicTopicSerializer
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -226,6 +226,7 @@ en:
|
||||||
placeholder: "type the topic title here"
|
placeholder: "type the topic title here"
|
||||||
|
|
||||||
queue:
|
queue:
|
||||||
|
topic: "Topic:"
|
||||||
approve: 'Approve Post'
|
approve: 'Approve Post'
|
||||||
reject: 'Reject Post'
|
reject: 'Reject Post'
|
||||||
title: "Needs Approval"
|
title: "Needs Approval"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
require_dependency 'queued_posts_controller'
|
||||||
|
require_dependency 'queued_post'
|
||||||
|
|
||||||
describe QueuedPostsController do
|
describe QueuedPostsController do
|
||||||
context 'without authentication' do
|
context 'without authentication' do
|
||||||
|
@ -24,5 +26,34 @@ describe QueuedPostsController do
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
context 'update' do
|
||||||
|
let!(:user) { log_in(:moderator) }
|
||||||
|
let(:qp) { Fabricate(:queued_post) }
|
||||||
|
|
||||||
|
context 'approved' do
|
||||||
|
it 'updates the post to approved' do
|
||||||
|
|
||||||
|
xhr :put, :update, id: qp.id, queued_post: { state: 'approved' }
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
qp.reload
|
||||||
|
expect(qp.state).to eq(QueuedPost.states[:approved])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'rejected' do
|
||||||
|
it 'updates the post to approved' do
|
||||||
|
|
||||||
|
xhr :put, :update, id: qp.id, queued_post: { state: 'rejected' }
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
qp.reload
|
||||||
|
expect(qp.state).to eq(QueuedPost.states[:rejected])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
18
spec/fabricators/queued_post_fabricator.rb
Normal file
18
spec/fabricators/queued_post_fabricator.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Fabricator(:queued_post) do
|
||||||
|
queue 'new_post'
|
||||||
|
state QueuedPost.states[:new]
|
||||||
|
user
|
||||||
|
topic
|
||||||
|
raw 'This post should be queued up'
|
||||||
|
post_options do
|
||||||
|
{ reply_to_post_number: 1,
|
||||||
|
via_email: true,
|
||||||
|
raw_email: 'store_me',
|
||||||
|
auto_track: true,
|
||||||
|
custom_fields: { hello: 'world' },
|
||||||
|
cooking_options: { cat: 'hat' },
|
||||||
|
cook_method: Post.cook_methods[:raw_html],
|
||||||
|
image_sizes: {"http://foo.bar/image.png" => {"width" => 0, "height" => 222}} }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -7,22 +7,7 @@ describe QueuedPost do
|
||||||
let(:topic) { Fabricate(:topic) }
|
let(:topic) { Fabricate(:topic) }
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
let(:qp) { QueuedPost.create(queue: 'new_post',
|
let(:qp) { Fabricate(:queued_post, topic: topic, user: user) }
|
||||||
state: QueuedPost.states[:new],
|
|
||||||
user_id: user.id,
|
|
||||||
topic_id: topic.id,
|
|
||||||
raw: 'This post should be queued up',
|
|
||||||
post_options: {
|
|
||||||
reply_to_post_number: 1,
|
|
||||||
via_email: true,
|
|
||||||
raw_email: 'store_me',
|
|
||||||
auto_track: true,
|
|
||||||
custom_fields: { hello: 'world' },
|
|
||||||
cooking_options: { cat: 'hat' },
|
|
||||||
cook_method: Post.cook_methods[:raw_html],
|
|
||||||
not_create_option: true,
|
|
||||||
image_sizes: {"http://foo.bar/image.png" => {"width" => 0, "height" => 222}}
|
|
||||||
}) }
|
|
||||||
|
|
||||||
it "returns the appropriate options for posting" do
|
it "returns the appropriate options for posting" do
|
||||||
create_options = qp.create_options
|
create_options = qp.create_options
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { acceptance } from "helpers/qunit-helpers";
|
||||||
acceptance("View Topic");
|
acceptance("View Topic");
|
||||||
|
|
||||||
test("Enter a Topic", () => {
|
test("Enter a Topic", () => {
|
||||||
visit("/t/internationalization-localization/280");
|
visit("/t/internationalization-localization/280/1");
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
ok(exists("#topic"), "The topic was rendered");
|
ok(exists("#topic"), "The topic was rendered");
|
||||||
ok(exists("#topic .post-cloak"), "The topic has cloaked posts");
|
ok(exists("#topic .post-cloak"), "The topic has cloaked posts");
|
||||||
|
|
|
@ -173,6 +173,14 @@ export default function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.get('/fruits/:id', function() {
|
||||||
|
return response({
|
||||||
|
__rest_serializer: "1",
|
||||||
|
fruit: {id: 1, name: 'apple', farmer_id: 1},
|
||||||
|
farmers: [{id: 1, name: 'Evil Trout'}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.get('/widgets/:widget_id', function(request) {
|
this.get('/widgets/:widget_id', function(request) {
|
||||||
const w = _widgets.findBy('id', parseInt(request.params.widget_id));
|
const w = _widgets.findBy('id', parseInt(request.params.widget_id));
|
||||||
if (w) {
|
if (w) {
|
||||||
|
|
|
@ -19,23 +19,51 @@ test('munging', function() {
|
||||||
|
|
||||||
test('update', function() {
|
test('update', function() {
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
|
|
||||||
store.find('widget', 123).then(function(widget) {
|
store.find('widget', 123).then(function(widget) {
|
||||||
equal(widget.get('name'), 'Trout Lure');
|
equal(widget.get('name'), 'Trout Lure');
|
||||||
widget.update({ name: 'new name' }).then(function() {
|
|
||||||
|
ok(!widget.get('isSaving'));
|
||||||
|
const promise = widget.update({ name: 'new name' });
|
||||||
|
ok(widget.get('isSaving'));
|
||||||
|
promise.then(function() {
|
||||||
|
ok(!widget.get('isSaving'));
|
||||||
equal(widget.get('name'), 'new name');
|
equal(widget.get('name'), 'new name');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('updating simultaneously', function() {
|
||||||
|
expect(2);
|
||||||
|
|
||||||
|
const store = createStore();
|
||||||
|
store.find('widget', 123).then(function(widget) {
|
||||||
|
|
||||||
|
const firstPromise = widget.update({ name: 'new name' });
|
||||||
|
const secondPromise = widget.update({ name: 'new name' });
|
||||||
|
firstPromise.then(function() {
|
||||||
|
ok(true, 'the first promise succeeeds');
|
||||||
|
});
|
||||||
|
|
||||||
|
secondPromise.catch(function() {
|
||||||
|
ok(true, 'the second promise fails');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('save new', function() {
|
test('save new', function() {
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
const widget = store.createRecord('widget');
|
const widget = store.createRecord('widget');
|
||||||
|
|
||||||
ok(widget.get('isNew'), 'it is a new record');
|
ok(widget.get('isNew'), 'it is a new record');
|
||||||
ok(!widget.get('isCreated'), 'it is not created');
|
ok(!widget.get('isCreated'), 'it is not created');
|
||||||
|
ok(!widget.get('isSaving'));
|
||||||
|
|
||||||
widget.save({ name: 'Evil Widget' }).then(function() {
|
const promise = widget.save({ name: 'Evil Widget' });
|
||||||
|
ok(widget.get('isSaving'));
|
||||||
|
|
||||||
|
promise.then(function() {
|
||||||
|
ok(!widget.get('isSaving'));
|
||||||
ok(widget.get('id'), 'it has an id');
|
ok(widget.get('id'), 'it has an id');
|
||||||
ok(widget.get('name'), 'Evil Widget');
|
ok(widget.get('name'), 'Evil Widget');
|
||||||
ok(widget.get('isCreated'), 'it is created');
|
ok(widget.get('isCreated'), 'it is created');
|
||||||
|
@ -43,6 +71,23 @@ test('save new', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('creating simultaneously', function() {
|
||||||
|
expect(2);
|
||||||
|
|
||||||
|
const store = createStore();
|
||||||
|
const widget = store.createRecord('widget');
|
||||||
|
|
||||||
|
const firstPromise = widget.save({ name: 'Evil Widget' });
|
||||||
|
const secondPromise = widget.save({ name: 'Evil Widget' });
|
||||||
|
firstPromise.then(function() {
|
||||||
|
ok(true, 'the first promise succeeeds');
|
||||||
|
});
|
||||||
|
|
||||||
|
secondPromise.catch(function() {
|
||||||
|
ok(true, 'the second promise fails');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('destroyRecord', function() {
|
test('destroyRecord', function() {
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
store.find('widget', 123).then(function(widget) {
|
store.find('widget', 123).then(function(widget) {
|
||||||
|
|
|
@ -88,3 +88,11 @@ test('destroyRecord', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('find embedded', function() {
|
||||||
|
const store = createStore();
|
||||||
|
store.find('fruit', 1).then(function(f) {
|
||||||
|
ok(f.get('farmer'), 'it has the embedded object');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue