Allow renaming of tags

This commit is contained in:
James Allen 2016-01-28 18:18:22 +00:00
parent 1a86e69d1f
commit 1bd5aef85f
9 changed files with 201 additions and 44 deletions

View file

@ -27,3 +27,15 @@ module.exports =
TagsHandler.deleteTag user_id, tag_id, (error) ->
return next(error) if error?
res.status(204).end()
renameTag: (req, res, next) ->
user_id = req.session.user._id
tag_id = req.params.tag_id
name = req.body?.name
if !name?
return res.status(400).end()
else
logger.log {user_id, tag_id, name}, "renaming tag"
TagsHandler.renameTag user_id, tag_id, name, (error) ->
return next(error) if error?
res.status(204).end()

View file

@ -5,6 +5,23 @@ logger = require("logger-sharelatex")
oneSecond = 1000
module.exports =
renameTag: (user_id, tag_id, name, callback = (error) ->) ->
url = "#{settings.apis.tags.url}/user/#{user_id}/tag/#{tag_id}/rename"
request.post {
url: url
json:
name: name
}, (err, res, body) ->
if err?
logger.err {err, user_id, tag_id, name}, "error renaming tag in tag api"
return callback(err)
else if res.statusCode >= 200 and res.statusCode < 300
return callback(null)
else
err = new Error("tags api returned a failure status code: #{res.statusCode}")
logger.err {err, user_id, tag_id, name}, "tags api returned failure status code: #{res.statusCode}"
return callback(err)
deleteTag: (user_id, tag_id, callback = (error) ->) ->
url = "#{settings.apis.tags.url}/user/#{user_id}/tag/#{tag_id}"
request.del url, (err, res, body) ->

View file

@ -134,6 +134,7 @@ module.exports = class Router
webRouter.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags
webRouter.post '/project/:project_id/tag', AuthenticationController.requireLogin(), TagsController.processTagsUpdate
webRouter.delete '/tag/:tag_id', AuthenticationController.requireLogin(), TagsController.deleteTag
webRouter.post '/tag/:tag_id/rename', AuthenticationController.requireLogin(), TagsController.renameTag
# Deprecated in favour of /internal/project/:project_id but still used by versioning
apiRouter.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails

View file

@ -56,6 +56,35 @@ script(type='text/ng-template', id='deleteTagModalTemplate')
span(ng-show="state.inflight") #{translate("deleting")}...
span(ng-show="!state.inflight") #{translate("delete")}
script(type='text/ng-template', id='renameTagModalTemplate')
.modal-header
button.close(
type="button"
data-dismiss="modal"
ng-click="cancel()"
) &times;
h3 #{translate("rename_tag")}
.modal-body
form(name="renameTagForm", novalidate)
input.form-control(
type="text",
placeholder="Tag Name",
ng-model="inputs.tagName",
required,
on-enter="rename()",
focus-on="open"
)
.modal-footer
.modal-footer-left
span.text-danger.error(ng-show="state.error") #{translate("generic_something_went_wrong")}
button.btn.btn-default(ng-click="cancel()") #{translate("cancel")}
button.btn.btn-primary(
ng-click="rename()",
ng-disabled="renameTagForm.$invalid || state.inflight"
)
span(ng-show="!state.inflight") #{translate("rename")}
span(ng-show="state.inflight") #{translate("renaming")}...
script(type='text/ng-template', id='renameProjectModalTemplate')
.modal-header
button.close(

View file

@ -74,10 +74,10 @@
role="menu"
)
li
a(href)
a(href, ng-click="renameTag(tag)", stop-propagation="click")
| #{translate("rename")}
li
a(href, ng-click="deleteTag(tag)")
a(href, ng-click="deleteTag(tag)", stop-propagation="click")
| #{translate("delete")}
li(ng-cloak)
a.tag(href, ng-click="openNewTagModal()")

View file

@ -1,23 +1,6 @@
define [
"base"
], (App) ->
App.controller 'NewTagModalController', ($scope, $modalInstance, $timeout) ->
$scope.inputs =
newTagName: ""
$modalInstance.opened.then () ->
$timeout () ->
$scope.$broadcast "open"
, 200
$scope.create = () ->
$modalInstance.close($scope.inputs.newTagName)
$scope.cancel = () ->
$modalInstance.dismiss('cancel')
App.controller 'RenameProjectModalController', ($scope, $modalInstance, $timeout, projectName) ->
$scope.inputs =
projectName: projectName
@ -102,28 +85,3 @@ define [
$scope.onComplete = (error, name, response) ->
if response.project_id?
window.location = '/project/' + response.project_id
App.controller 'DeleteTagModalController', ($scope, $modalInstance, $http, tag) ->
$scope.tag = tag
$scope.state =
inflight: false
error: false
$scope.delete = () ->
$scope.state.inflight = true
$scope.state.error = false
$http({
method: "DELETE"
url: "/tag/#{tag._id}"
headers:
"X-CSRF-Token": window.csrfToken
})
.success () ->
$scope.state.inflight = false
$modalInstance.close()
.error () ->
$scope.state.inflight = false
$scope.state.error = true
$scope.cancel = () ->
$modalInstance.dismiss('cancel')

View file

@ -26,6 +26,17 @@ define [
modalInstance.result.then () ->
$scope.tags = $scope.tags.filter (t) -> t != tag
$scope.renameTag = (tag) ->
modalInstance = $modal.open(
templateUrl: "renameTagModalTemplate"
controller: "RenameTagModalController"
resolve:
tag: () -> tag
existing_tags: () -> $scope.tags
)
modalInstance.result.then (new_name) ->
tag.name = new_name
App.controller "TagDropdownItemController", ($scope) ->
$scope.recalculateProjectsInTag = () ->
$scope.areSelectedProjectsInTag = false
@ -49,3 +60,75 @@ define [
$scope.$watch "selectedProjects", () ->
$scope.recalculateProjectsInTag()
$scope.recalculateProjectsInTag()
App.controller 'NewTagModalController', ($scope, $modalInstance, $timeout) ->
$scope.inputs =
newTagName: ""
$modalInstance.opened.then () ->
$timeout () ->
$scope.$broadcast "open"
, 200
$scope.create = () ->
$modalInstance.close($scope.inputs.newTagName)
$scope.cancel = () ->
$modalInstance.dismiss('cancel')
App.controller 'RenameTagModalController', ($scope, $modalInstance, $timeout, $http, tag, existing_tags) ->
$scope.inputs =
tagName: tag.name
$scope.state =
inflight: false
error: false
$modalInstance.opened.then () ->
$timeout () ->
$scope.$broadcast "open"
, 200
$scope.rename = () ->
name = $scope.inputs.tagName
$scope.state.inflight = true
$scope.state.error = false
$http
.post "/tag/#{tag._id}/rename", {
_csrf: window.csrfToken,
name: name
}
.success () ->
$scope.state.inflight = false
$modalInstance.close(name)
.error () ->
$scope.state.inflight = false
$scope.state.error = true
$scope.cancel = () ->
$modalInstance.dismiss('cancel')
App.controller 'DeleteTagModalController', ($scope, $modalInstance, $http, tag) ->
$scope.tag = tag
$scope.state =
inflight: false
error: false
$scope.delete = () ->
$scope.state.inflight = true
$scope.state.error = false
$http({
method: "DELETE"
url: "/tag/#{tag._id}"
headers:
"X-CSRF-Token": window.csrfToken
})
.success () ->
$scope.state.inflight = false
$modalInstance.close()
.error () ->
$scope.state.inflight = false
$scope.state.error = true
$scope.cancel = () ->
$modalInstance.dismiss('cancel')

View file

@ -15,6 +15,7 @@ describe 'Tags controller', ->
addTag: sinon.stub().callsArgWith(3)
removeProject: sinon.stub().callsArgWith(3)
deleteTag: sinon.stub().callsArg(2)
renameTag: sinon.stub().callsArg(3)
@controller = SandboxedModule.require modulePath, requires:
"./TagsHandler":@handler
'logger-sharelatex':
@ -68,3 +69,34 @@ describe 'Tags controller', ->
it "should return 204 status code", ->
@res.status.calledWith(204).should.equal true
@res.end.called.should.equal true
describe "renameTag", ->
beforeEach ->
@req.params.tag_id = @tag_id = "tag-id-123"
@req.session.user._id = @user_id = "user-id-123"
describe "with a name", ->
beforeEach ->
@req.body = name: @name = "new-name"
@controller.renameTag @req, @res
it "should delete the tag in the backend", ->
@handler.renameTag
.calledWith(@user_id, @tag_id, @name)
.should.equal true
it "should return 204 status code", ->
@res.status.calledWith(204).should.equal true
@res.end.called.should.equal true
describe "without a name", ->
beforeEach ->
@controller.renameTag @req, @res
it "should not call the backend", ->
@handler.renameTag.called.should.equal false
it "should return 400 (bad request) status code", ->
@res.status.calledWith(400).should.equal true
@res.end.called.should.equal true

View file

@ -127,3 +127,28 @@ describe 'TagsHandler', ->
it "should call the callback with an Error", ->
@callback.calledWith(new Error()).should.equal true
describe "renameTag", ->
describe "successfully", ->
beforeEach ->
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 204}, "")
@handler.renameTag user_id, tag_id, @name = "new-name", @callback
it "should send a request to the tag backend", ->
@request.post
.calledWith({
url: "#{tagsUrl}/user/#{user_id}/tag/#{tag_id}/rename"
json:
name: @name
})
.should.equal true
it "should call the callback with no error", ->
@callback.calledWith(null).should.equal true
describe "with error", ->
beforeEach ->
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 500}, "")
@handler.renameTag user_id, tag_id, "name", @callback
it "should call the callback with an Error", ->
@callback.calledWith(new Error()).should.equal true