Add REST create method that errors if a multi already exists.

This commit is contained in:
Max Goodman
2013-05-17 17:21:49 -07:00
parent 1ac24bf9e6
commit 765087b4b7
4 changed files with 75 additions and 50 deletions

View File

@@ -93,23 +93,21 @@ class MultiApiController(RedditController, OAuth2ResourceController):
"""Fetch a multi's data and subreddit list by name."""
return self._format_multi(multi)
@require_oauth2_scope("subscribe")
@api_doc(api_section.multis, extends=GET_multi)
@validate(
VUser(),
VModhash(),
info=VMultiPath("multipath"),
data=VJSON("model"),
)
def PUT_multi(self, info, data):
"""Create or update a multi."""
if info['username'].lower() != c.user.name.lower():
def _write_multi_data(self, path_info, data, fail_if_exists=False):
if path_info['username'].lower() != c.user.name.lower():
raise RedditError('BAD_MULTI_NAME', code=400, fields="multipath")
try:
multi = LabeledMulti._byID(info['path'])
multi = LabeledMulti._byID(path_info['path'])
except tdb_cassandra.NotFound:
multi = LabeledMulti.create(info['path'], c.user)
multi = None
if multi:
if fail_if_exists:
raise RedditError('MULTI_EXISTS', code=409, fields="multipath")
else:
multi = LabeledMulti.create(path_info['path'], c.user)
if 'visibility' in data:
if data['visibility'] not in ('private', 'public'):
@@ -143,6 +141,32 @@ class MultiApiController(RedditController, OAuth2ResourceController):
raise RedditError('MULTI_TOO_MANY_SUBREDDITS', code=409)
multi._commit()
return multi
@require_oauth2_scope("subscribe")
@api_doc(api_section.multis, extends=GET_multi)
@validate(
VUser(),
VModhash(),
path_info=VMultiPath("multipath"),
data=VJSON("model"),
)
def POST_multi(self, path_info, data):
"""Create a multi. Responds with 409 Conflict if it already exists."""
multi = self._write_multi_data(path_info, data, fail_if_exists=True)
return self._format_multi(multi)
@require_oauth2_scope("subscribe")
@api_doc(api_section.multis, extends=GET_multi)
@validate(
VUser(),
VModhash(),
path_info=VMultiPath("multipath"),
data=VJSON("model"),
)
def PUT_multi(self, path_info, data):
"""Create or update a multi."""
multi = self._write_multi_data(path_info, data)
return self._format_multi(multi)
@require_oauth2_scope("subscribe")

View File

@@ -124,6 +124,7 @@ error_list = dict((
('BAD_MULTI_PATH', _('invalid multi path')),
('BAD_MULTI_NAME', _('%(reason)s')),
('MULTI_NOT_FOUND', _('that multireddit doesn\'t exist')),
('MULTI_EXISTS', _('that multireddit already exists')),
('MULTI_CANNOT_EDIT', _('you can\'t change that multireddit')),
('MULTI_TOO_MANY_SUBREDDITS', _('no more space for subreddits in that multireddit')),
('MULTI_SPECIAL_SUBREDDIT', _("can't add special subreddit %(path)s")),

View File

@@ -216,7 +216,6 @@ Note: there are a couple of places outside of your subreddit where someone can c
create_multi = _('create a new multi'),
awesomeness_goes_here = _('awesomeness goes here'),
add_multi_sr = _('add a subreddit to your multi.'),
multi_already_exists = _('that multi already exists'),
)
class StringHandler(object):

View File

@@ -56,7 +56,8 @@ r.multi.MultiReddit = Backbone.Model.extend({
return r.utils.joinURLs('/api/multi', this.id)
},
initialize: function() {
initialize: function(attributes, options) {
this.uncreated = options && !!options.isNew
this.subreddits = new r.multi.MultiRedditList(this.get('subreddits'))
this.subreddits.url = this.url() + '/r/'
this.on('change:subreddits', function(model, value) {
@@ -77,6 +78,21 @@ r.multi.MultiReddit = Backbone.Model.extend({
return data
},
isNew: function() {
return this.uncreated
},
sync: function(method, model, options) {
var res = Backbone.sync.apply(this, arguments)
if (method == 'create') {
res.done(_.bind(function() {
// upon successful creation, unset new flag
this.uncreated = false
}, this))
}
return res
},
addSubreddit: function(name, options) {
this.subreddits.create({name: name}, options)
},
@@ -101,14 +117,6 @@ r.multi.MyMultiCollection = Backbone.Collection.extend({
return model.get('path').toLowerCase()
},
create: function(attributes, options) {
if ('name' in attributes) {
attributes['path'] = this.pathByName(attributes['name'])
delete attributes['name']
}
Backbone.Collection.prototype.create.call(this, attributes, options)
},
parse: function(data) {
return _.map(data, function(multiData) {
return r.multi.multis.reify(multiData)
@@ -117,10 +125,6 @@ r.multi.MyMultiCollection = Backbone.Collection.extend({
pathByName: function(name) {
return '/user/' + r.config.logged + '/m/' + name
},
touchByName: function(name) {
return r.multi.multis.touch(this.pathByName(name))
}
})
@@ -306,7 +310,9 @@ r.multi.MultiDetails = Backbone.View.extend({
el: $copyForm,
navOnCreate: true,
createMulti: _.bind(function(name) {
var newMulti = r.multi.mine.touchByName(name)
var newMulti = new r.multi.MultiReddit({
path: r.multi.mine.pathByName(name)
}, {isNew: true})
this.model.copyTo(newMulti)
return newMulti
}, this)
@@ -431,30 +437,25 @@ r.multi.MultiCreateForm = Backbone.View.extend({
if (this.options.createMulti) {
newMulti = this.options.createMulti(name)
} else {
newMulti = r.multi.mine.touchByName(name)
var newMulti = new r.multi.MultiReddit({
path: r.multi.mine.pathByName(name)
}, {isNew: true})
}
// check if the multi already exists
newMulti.fetch({beforeSend: this.showWorkingDeferred})
.done(_.bind(function() {
this.showError(r.strings('multi_already_exists'))
}, this))
.fail(_.bind(function() {
r.multi.mine.create(newMulti, {
wait: true,
beforeSend: this.showWorkingDeferred,
success: _.bind(function(multi) {
this.trigger('create', multi)
if (this.options.navOnCreate) {
window.location = multi.get('path') + '#created'
}
}, this),
error: _.bind(function(multi, xhr) {
var resp = JSON.parse(xhr.responseText)
this.showError(resp.explanation)
}, this)
})
}, this))
r.multi.mine.create(newMulti, {
wait: true,
beforeSend: this.showWorkingDeferred,
success: _.bind(function(multi) {
this.trigger('create', multi)
if (this.options.navOnCreate) {
window.location = multi.get('path') + '#created'
}
}, this),
error: _.bind(function(multi, xhr) {
var resp = JSON.parse(xhr.responseText)
this.showError(resp.explanation)
}, this)
})
},
showError: function(error) {