Просмотр исходного кода

Add opt-out action to beta page

Shane Kilkelly 10 лет назад
Родитель
Сommit
8f1fec8c4f

+ 12 - 2
services/web/app/coffee/Features/BetaProgram/BetaProgramController.coffee

@@ -14,11 +14,21 @@ module.exports = BetaProgramController =
 		BetaProgramHandler.optIn user_id, (err) ->
 			if err
 				return next(err)
-			return res.redirect "/beta/opt-in"
+			return res.redirect "/beta/participate"
+
+	optOut: (req, res, next) ->
+		user_id = req?.session?.user?._id
+		logger.log {user_id}, "user opting out of beta program"
+		if !user_id
+			return next(new Error("no user id in session"))
+		BetaProgramHandler.optOut user_id, (err) ->
+			if err
+				return next(err)
+			return res.redirect "/beta/participate"
 
 	optInPage: (req, res, next)->
 		user_id = req.session?.user?._id
-		logger.log {user_id}, "showing beta opt-in page for user"
+		logger.log {user_id}, "showing beta participation page for user"
 		UserLocator.findById user_id, (err, user)->
 			if err
 				logger.err {err, user_id}, "error fetching user"

+ 13 - 0
services/web/app/coffee/Features/BetaProgram/BetaProgramHandler.coffee

@@ -16,3 +16,16 @@ module.exports = BetaProgramHandler =
 					logger.err {err, user_id}, "problem adding user to beta"
 					return callback(err)
 				return callback(null)
+
+	optOut: (user_id, callback=(err)->) ->
+		User.findById user_id, (err, user) ->
+			if err
+				logger.err {err, user_id}, "problem removing user from beta"
+				return callback(err)
+			metrics.inc "beta-program.opt-out"
+			user.betaProgram = false
+			user.save (err) ->
+				if err
+					logger.err {err, user_id}, "problem removing user from beta"
+					return callback(err)
+				return callback(null)

+ 2 - 1
services/web/app/coffee/router.coffee

@@ -198,8 +198,9 @@ module.exports = class Router
 		webRouter.post "/project/:Project_id/references/index", AuthorizationMiddlewear.ensureUserCanReadProject, ReferencesController.index
 		webRouter.post "/project/:Project_id/references/indexAll", AuthorizationMiddlewear.ensureUserCanReadProject, ReferencesController.indexAll
 
-		webRouter.get "/beta/opt-in",  AuthenticationController.requireLogin(), BetaProgramController.optInPage
+		webRouter.get "/beta/participate",  AuthenticationController.requireLogin(), BetaProgramController.optInPage
 		webRouter.post "/beta/opt-in", AuthenticationController.requireLogin(), BetaProgramController.optIn
+		webRouter.post "/beta/opt-out", AuthenticationController.requireLogin(), BetaProgramController.optOut
 
 		#Admin Stuff
 		webRouter.get  '/admin', AuthorizationMiddlewear.ensureUserIsSiteAdmin, AdminController.index

+ 9 - 2
services/web/app/views/beta_program/opt_in.jade

@@ -27,8 +27,15 @@ block content
 									.col-md-12
 										if user.betaProgram
 											p #{translate("beta_program_already_participating")}
-											.form-group
-												a(href="/project").btn.btn-info #{translate("back_to_your_projects")}
+											form(method="post", action="/beta/opt-out", novalidate)
+												.form-group
+													input(type="hidden", name="_csrf", value=csrfToken)
+													button.btn.btn-primary(
+														type="submit"
+													)
+														span #{translate("beta_program_opt_out_action")}
+												.form-group
+													a(href="/project").btn.btn-info #{translate("back_to_your_projects")}
 										else
 											form(method="post", action="/beta/opt-in", novalidate)
 												.form-group

+ 41 - 3
services/web/test/UnitTests/coffee/BetaProgram/BetaProgramControllerTests.coffee

@@ -21,6 +21,7 @@ describe "BetaProgramController", ->
 		@BetaProgramController = SandboxedModule.require modulePath, requires:
 			"./BetaProgramHandler": @BetaProgramHandler = {
 				optIn: sinon.stub()
+				optOut: sinon.stub()
 			},
 			"../User/UserLocator": @UserLocator = {
 				findById: sinon.stub()
@@ -44,10 +45,10 @@ describe "BetaProgramController", ->
 		beforeEach ->
 			@BetaProgramHandler.optIn.callsArgWith(1, null)
 
-		it "should redirect to '/beta/opt-in'", () ->
+		it "should redirect to '/beta/participate'", () ->
 			@BetaProgramController.optIn @req, @res, @next
 			@res.redirect.callCount.should.equal 1
-			@res.redirect.firstCall.args[0].should.equal "/beta/opt-in"
+			@res.redirect.firstCall.args[0].should.equal "/beta/participate"
 
 		it "should not call next with an error", () ->
 			@BetaProgramController.optIn @req, @res, @next
@@ -66,7 +67,7 @@ describe "BetaProgramController", ->
 			beforeEach ->
 				@BetaProgramHandler.optIn.callsArgWith(1, new Error('woops'))
 
-			it "should not redirect to '/'", () ->
+			it "should not redirect to '/beta/participate'", () ->
 				@BetaProgramController.optIn @req, @res, @next
 				@res.redirect.callCount.should.equal 0
 
@@ -75,6 +76,43 @@ describe "BetaProgramController", ->
 				@next.callCount.should.equal 1
 				@next.firstCall.args[0].should.be.instanceof Error
 
+	describe "optOut", ->
+
+		beforeEach ->
+			@BetaProgramHandler.optOut.callsArgWith(1, null)
+
+		it "should redirect to '/beta/participate'", () ->
+			@BetaProgramController.optOut @req, @res, @next
+			@res.redirect.callCount.should.equal 1
+			@res.redirect.firstCall.args[0].should.equal "/beta/participate"
+
+		it "should not call next with an error", () ->
+			@BetaProgramController.optOut @req, @res, @next
+			@next.callCount.should.equal 0
+
+		it "should not call next with an error", () ->
+			@BetaProgramController.optOut @req, @res, @next
+			@next.callCount.should.equal 0
+
+		it "should call BetaProgramHandler.optOut", () ->
+			@BetaProgramController.optOut @req, @res, @next
+			@BetaProgramHandler.optOut.callCount.should.equal 1
+
+		describe "when BetaProgramHandler.optOut produces an error", ->
+
+			beforeEach ->
+				@BetaProgramHandler.optOut.callsArgWith(1, new Error('woops'))
+
+			it "should not redirect to '/beta/participate'", () ->
+				@BetaProgramController.optOut @req, @res, @next
+				@res.redirect.callCount.should.equal 0
+
+			it "should produce an error", () ->
+				@BetaProgramController.optOut @req, @res, @next
+				@next.callCount.should.equal 1
+				@next.firstCall.args[0].should.be.instanceof Error
+
+
 	describe "optInPage", ->
 
 		beforeEach ->

+ 35 - 0
services/web/test/UnitTests/coffee/BetaProgram/BetaProgramHandlerTests.coffee

@@ -34,6 +34,7 @@ describe 'BetaProgramHandler', ->
 	describe "optIn", ->
 
 		beforeEach ->
+			@user.betaProgram = false
 			@call = (callback) =>
 				@handler.optIn @user_id, callback
 
@@ -63,3 +64,37 @@ describe 'BetaProgramHandler', ->
 					expect(err).to.not.equal null
 					expect(err).to.be.instanceof Error
 					done()
+
+	describe "optOut", ->
+
+		beforeEach ->
+			@user.betaProgram = true
+			@call = (callback) =>
+				@handler.optOut @user_id, callback
+
+		it "should set betaProgram = true on user object", (done) ->
+			@call (err) =>
+				@user.betaProgram.should.equal false
+				done()
+
+		it "should call user.save", (done) ->
+			@call (err) =>
+				@user.save.callCount.should.equal 1
+				done()
+
+		it "should not produce an error", (done) ->
+			@call (err) =>
+				expect(err).to.equal null
+				expect(err).to.not.be.instanceof Error
+				done()
+
+		describe "when user.save produces an error", ->
+
+			beforeEach ->
+				@user.save.callsArgWith(0, new Error('woops'))
+
+			it "should produce an error", (done) ->
+				@call (err) =>
+					expect(err).to.not.equal null
+					expect(err).to.be.instanceof Error
+					done()