James Allen 12 лет назад
Родитель
Сommit
be48ab2a30

+ 2 - 1
services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee

@@ -26,7 +26,8 @@ module.exports =
 
 	addUserToProject: (project_id, email, privilegeLevel, callback)->
 		emails = mimelib.parseAddresses(email)
-		email = emails[0].address?.toLowerCase()
+		email = emails[0]?.address?.toLowerCase()
+		return callback(new Error("no valid email provided")) if !email?
 		self = @
 		User.findOne {'email':email}, (err, user)->
 			async.waterfall [

+ 1 - 1
services/web/app/coffee/Features/Editor/EditorController.coffee

@@ -138,7 +138,7 @@ module.exports = EditorController =
 				CollaboratorsHandler.addUserToProject project_id, email, privileges, (err, user)=>
 					ProjectEntityHandler.flushProjectToThirdPartyDataStore project_id, "", ->
 					EditorRealTimeController.emitToRoom(project_id, 'userAddedToProject', user, privileges)
-					callback null, true
+					callback null, ProjectEditorHandler.buildUserModelView(user, privileges)
 
 	removeUserFromProject: (project_id, user_id, callback)->
 		CollaboratorsHandler.removeUserFromProject project_id, user_id, =>

+ 2 - 27
services/web/app/views/project/editor.jade

@@ -37,6 +37,8 @@ block content
 
 		include ./editor/header
 
+		include ./editor/share
+
 		#ide-body(ng-cloak, layout="main", ng-hide="state.loading")
 			.ui-layout-west
 				include ./editor/file-tree
@@ -45,33 +47,6 @@ block content
 				include ./editor/editor
 				include ./editor/track-changes
 
-	//- #loadingScreen
-	//- 	h3 Loading...
-	//- 	p#loadingMessage Loading editor
-
-	//- #errorMessages
-	//- 	#connectionLostMessage(style="display: none;")
-	//- 		| Lost connection. 
-	//- 		span#trying-reconnect
-	//- 			| Reconnecting in 
-	//- 			span#reconnection-countdown ? 
-	//- 			|  seconds. 
-	//- 			a(href='#')#try-reconnect-now Try now.
-	//- 		span#reconnecting
-	//- 			| Reconnecting...
-
-	//- 	#savingProblems(style="display: none")
-	//- 		| Saving...
-	
-	//- div#toolbar.sidebar-navigation
-	//- 	ul#tabs
-	//- 	#toolbar-footer
-
-	//- #tab-content.tab-content
-
-	//- include ../templates
-	//- include ../templates/dropbox
-
 	script(src='/socket.io/socket.io.js')
 
 	script(type='text/javascript').

+ 7 - 1
services/web/app/views/project/editor/header.jade

@@ -13,7 +13,13 @@ header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading")
 		i.fa.fa-pencil
 
 	.toolbar-right
-		a.btn.btn-full-height(href='#', tooltip="Share", tooltip-placement="bottom")
+		a.btn.btn-full-height(
+			href,
+			tooltip="Share",
+			tooltip-placement="bottom",
+			ng-click="openShareProjectModal()",
+			ng-controller="ShareController"
+		)
 			i.fa.fa-fw.fa-group
 		a.btn.btn-full-height(
 			href,

+ 61 - 0
services/web/app/views/project/editor/share.jade

@@ -0,0 +1,61 @@
+script(type='text/ng-template', id='shareProjectModalTemplate')
+	.modal-header
+		h3 Share Project
+	.modal-body.modal-body-share
+		.container-fluid
+			.row.public-access-level
+				.col-md-9 This project is private and can only be accessed by the people below.
+				.col-md-3.text-right
+					a(href) Make public
+			.row.project-member
+				.col-md-8 {{ project.owner.email }}
+				.text-right(
+					ng-class="{'col-md-3': project.members.length > 0, 'col-md-4': project.members.length == 0}"
+				) Owner
+			.row.project-member(ng-repeat="member in project.members")
+				.col-md-8 {{ member.email }}
+				.col-md-3.text-right
+					span(ng-show="member.privileges == 'readAndWrite'") Can Edit
+					span(ng-show="member.privileges == 'readOnly'") Read Only
+				.col-md-1
+					a(
+						href
+						tooltip="Remove collaborator"
+						tooltip-placement="bottom"
+						ng-click="removeMember(member)"
+					)
+						i.fa.fa-times
+			.row.invite-controls
+				form(ng-show="canAddCollaborators")
+					.small Share with your collaborators
+					.form-group
+						input.form-control(
+							type="email"
+							placeholder="Enter email address..."
+							ng-model="inputs.email"
+							focus-on="open"
+						)
+					.form-group
+						.pull-right
+							select.privileges.form-control(
+								ng-model="inputs.privileges"
+								name="privileges"
+							)
+								option(value="readAndWrite") Can Edit
+								option(value="readOnly") Read Only
+							|   
+							button.btn.btn-info(
+								type="submit"
+								ng-click="addMember()"
+							) Share
+				div.text-center(ng-hide="canAddCollaborators")
+					p You need to upgrade your account to add more collaborators.
+					a.btn.btn-info(href) Start Free Trial
+
+	.modal-footer
+		.modal-footer-left
+			i.fa.fa-refresh.fa-spin(ng-show="state.inflight")
+			span.text-danger.error(ng-show="state.error") {{ state.error }}
+		button.btn.btn-primary(
+			ng-click="done()"
+		) Done

+ 1 - 0
services/web/public/coffee/app/ide.coffee

@@ -7,6 +7,7 @@ define [
 	"ide/online-users/OnlineUsersManager"
 	"ide/track-changes/TrackChangesManager"
 	"ide/pdf/PdfManager"
+	"ide/share/index"
 	"ide/directives/layout"
 	"ide/services/ide"
 	"directives/focus"

+ 11 - 0
services/web/public/coffee/app/ide/share/controllers/ShareController.coffee

@@ -0,0 +1,11 @@
+define [
+	"base"
+], (App) ->
+	App.controller "ShareController", ["$scope", "$modal", ($scope, $modal) ->
+		$scope.openShareProjectModal = () ->
+			$modal.open(
+				templateUrl: "shareProjectModalTemplate"
+				controller:  "ShareProjectModalController"
+				scope: $scope
+			)
+	]

+ 57 - 0
services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee

@@ -0,0 +1,57 @@
+define [
+	"base"
+], (App) ->
+	App.controller "ShareProjectModalController", ["$scope", "$modalInstance", "$timeout", "projectMembers", ($scope, $modalInstance, $timeout, projectMembers) ->
+		$scope.inputs = {
+			privileges: "readAndWrite"
+			email: ""
+		}
+		$scope.state = {
+			error: null
+			inflight: false
+		}
+
+		$modalInstance.opened.then () ->
+			$timeout () ->
+				$scope.$broadcast "open"
+			, 200
+
+		INFINITE_COLLABORATORS = -1
+		$scope.$watch "project.members.length", (noOfMembers) ->
+			allowedNoOfMembers = $scope.project.features.collaborators
+			$scope.canAddCollaborators = noOfMembers < allowedNoOfMembers or allowedNoOfMembers == INFINITE_COLLABORATORS
+
+		$scope.addMember = () ->
+			console.log "EMAIL", $scope.inputs.email
+			return if !$scope.inputs.email? or $scope.inputs.email == ""
+			$scope.state.error = null
+			$scope.state.inflight = true
+			projectMembers
+				.addMember($scope.inputs.email, $scope.inputs.privileges)
+				.then (user) ->
+					$scope.state.inflight = false
+					$scope.inputs.email = ""
+					console.log "GOT USER", user
+					$scope.project.members.push user
+				.catch () ->
+					$scope.state.inflight = false
+					$scope.state.error = "Sorry, something went wrong :("
+
+
+		$scope.removeMember = (member) ->
+			$scope.state.error = null
+			$scope.state.inflight = true
+			projectMembers
+				.removeMember(member)
+				.then () ->
+					$scope.state.inflight = false
+					index = $scope.project.members.indexOf(member)
+					return if index == -1
+					$scope.project.members.splice(index, 1)
+				.catch () ->
+					$scope.state.inflight = false
+					$scope.state.error = "Sorry, something went wrong :("
+
+		$scope.done = () ->
+			$modalInstance.close()
+	]

+ 5 - 0
services/web/public/coffee/app/ide/share/index.coffee

@@ -0,0 +1,5 @@
+define [
+	"ide/share/controllers/ShareController"
+	"ide/share/controllers/ShareProjectModalController"
+	"ide/share/services/projectMembers"
+], () ->

+ 30 - 0
services/web/public/coffee/app/ide/share/services/projectMembers.coffee

@@ -0,0 +1,30 @@
+define [
+	"base"
+], (App) ->
+	App.factory "projectMembers", ["ide", "$q", (ide, $q) ->
+		return {
+			removeMember: (member) ->
+				deferred = $q.defer()
+
+				ide.socket.emit "removeUserFromProject", member._id, (error) =>
+					if error?
+						return deferred.reject(error)
+					deferred.resolve()
+
+				return deferred.promise
+
+			addMember: (email, privileges) ->
+				deferred = $q.defer()
+
+				ide.socket.emit "addUserToProject", email, privileges, (error, user) =>
+					if error?
+						return deferred.reject(error)
+
+					if !user
+						deferred.reject()
+					else
+						deferred.resolve(user)
+
+				return deferred.promise
+		}
+	]

+ 1 - 0
services/web/public/stylesheets/app/editor.less

@@ -3,6 +3,7 @@
 @import "./editor/toolbar.less";
 @import "./editor/left-menu.less";
 @import "./editor/pdf.less";
+@import "./editor/share.less";
 
 .full-size {
 	position: absolute;

+ 49 - 0
services/web/public/stylesheets/app/editor/share.less

@@ -0,0 +1,49 @@
+.modal-body-share {
+	h3 {
+		border-bottom: 1px solid @gray-lighter;
+		padding-bottom: @line-height-computed / 4;
+		margin: 0;
+		font-size: 1rem;
+	}
+
+	.project-member, .public-access-level {
+		padding: (@line-height-computed / 2) 0;
+		border-bottom: 1px solid @gray-lighter;
+		font-size: 14px;
+	}
+
+	.public-access-level {
+		color: @gray;
+		padding-top: 0;
+		font-size: 12px;
+	}
+
+	.project-member {
+		&:hover {
+			background-color: @gray-lightest;
+		}
+	}
+
+	.invite-controls {
+		.small {
+			padding: 2px;
+		}
+		padding: @line-height-computed / 2;
+		background-color: @gray-lightest;
+		margin-top: @line-height-computed / 2;
+		form {
+			.form-group {
+				margin-bottom: @line-height-computed / 2;
+				&:last-child {
+					margin-bottom: 0;
+				}
+			}
+			.privileges {
+				display: inline-block;
+				width: auto;
+				height: 30px;
+				font-size: 14px;
+			}
+		}
+	}
+}

+ 4 - 0
services/web/public/stylesheets/components/modals.less

@@ -126,6 +126,10 @@
   .btn-block + .btn-block {
     margin-left: 0;
   }
+
+  .modal-footer-left {
+    float: left;
+  }
 }
 
 // Scale up the modal