mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-05 14:59:19 +00:00
WIP: track changes with token-access
This commit is contained in:
parent
b32088ee6b
commit
74c231826d
16 changed files with 134 additions and 31 deletions
|
@ -38,3 +38,13 @@ module.exports = CollaboratorsController =
|
|||
logger.err {projectId}, "error getting members for project"
|
||||
return next(err)
|
||||
res.json({members: members})
|
||||
|
||||
getTokenMembers: (req, res, next) ->
|
||||
projectId = req.params.Project_id
|
||||
logger.log {projectId}, "getting token members for project"
|
||||
CollaboratorsHandler.getTokenMembers projectId, (err, tokenMembers) ->
|
||||
tokenMembers = tokenMembers.slice(0, 100)
|
||||
if err?
|
||||
logger.err {projectId}, "error getting token members for project"
|
||||
return next(err)
|
||||
res.json({tokenMembers})
|
||||
|
|
|
@ -11,6 +11,7 @@ Errors = require "../Errors/Errors"
|
|||
EmailHelper = require "../Helpers/EmailHelper"
|
||||
ProjectEditorHandler = require "../Project/ProjectEditorHandler"
|
||||
Sources = require "../Authorization/Sources"
|
||||
ObjectId = require('mongojs').ObjectId
|
||||
|
||||
module.exports = CollaboratorsHandler =
|
||||
|
||||
|
@ -232,3 +233,31 @@ module.exports = CollaboratorsHandler =
|
|||
return callback(error)
|
||||
{owner, members} = ProjectEditorHandler.buildOwnerAndMembersViews(rawMembers)
|
||||
callback(null, members)
|
||||
|
||||
getTokenMembers: (projectId, callback=(err, members)->) ->
|
||||
logger.log {projectId}, "fetching all token members"
|
||||
CollaboratorsHandler.getTokenMembersWithPrivilegeLevels projectId, (error, rawTokenMembers) ->
|
||||
if error?
|
||||
logger.err {projectId, error}, "error getting token members for project"
|
||||
return callback(error)
|
||||
{_owner, tokenMembers} = ProjectEditorHandler.buildOwnerAndMembersViews(
|
||||
null,
|
||||
rawTokenMembers
|
||||
)
|
||||
callback(null, tokenMembers)
|
||||
|
||||
userIsTokenMember: (userId, projectId, callback=(err, isTokenMember)->) ->
|
||||
userId = ObjectId(userId.toString())
|
||||
projectId = ObjectId(projectId.toString())
|
||||
Project.findOne {
|
||||
_id: projectId,
|
||||
$or: [
|
||||
{tokenAccessReadOnly_refs: userId},
|
||||
{tokenAccessReadAndWrite_refs: userId}
|
||||
]
|
||||
}, {
|
||||
_id: 1
|
||||
}, (err, project) ->
|
||||
if err?
|
||||
return callback(err)
|
||||
callback(null, project?)
|
||||
|
|
|
@ -17,6 +17,13 @@ module.exports =
|
|||
CollaboratorsController.getAllMembers
|
||||
)
|
||||
|
||||
webRouter.get(
|
||||
'/project/:Project_id/token_members',
|
||||
AuthenticationController.requireLogin(),
|
||||
AuthorizationMiddlewear.ensureUserCanAdminProject,
|
||||
CollaboratorsController.getTokenMembers
|
||||
)
|
||||
|
||||
# invites
|
||||
webRouter.post(
|
||||
'/project/:Project_id/invite',
|
||||
|
|
|
@ -23,6 +23,7 @@ PackageVersions = require("../../infrastructure/PackageVersions")
|
|||
AnalyticsManager = require "../Analytics/AnalyticsManager"
|
||||
Sources = require "../Authorization/Sources"
|
||||
TokenAccessHandler = require '../TokenAccess/TokenAccessHandler'
|
||||
CollaboratorsHandler = require '../Collaborators/CollaboratorsHandler'
|
||||
|
||||
module.exports = ProjectController =
|
||||
|
||||
|
@ -247,6 +248,11 @@ module.exports = ProjectController =
|
|||
return cb(null, false)
|
||||
else
|
||||
return cb(null, true)
|
||||
isTokenMember: (cb) ->
|
||||
cb = underscore.once(cb)
|
||||
if !user_id?
|
||||
return cb()
|
||||
CollaboratorsHandler.userIsTokenMember user_id, project_id, cb
|
||||
}, (err, results)->
|
||||
if err?
|
||||
logger.err err:err, "error getting details for project page"
|
||||
|
@ -260,6 +266,7 @@ module.exports = ProjectController =
|
|||
logger.log project_id:project_id, daysSinceLastUpdated:daysSinceLastUpdated, "got db results for loading editor"
|
||||
|
||||
token = TokenAccessHandler.getRequestToken(req, project_id)
|
||||
isTokenMember = results.isTokenMember
|
||||
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel)->
|
||||
return next(error) if error?
|
||||
if !privilegeLevel? or privilegeLevel == PrivilegeLevels.NONE
|
||||
|
@ -304,6 +311,7 @@ module.exports = ProjectController =
|
|||
chatUrl: Settings.apis.chat.url
|
||||
anonymous: anonymous
|
||||
anonymousAccessToken: req._anonymousAccessToken
|
||||
isTokenMember: isTokenMember
|
||||
languages: Settings.languages
|
||||
themes: THEME_LIST
|
||||
maxDocLength: Settings.max_doc_length
|
||||
|
|
|
@ -51,13 +51,13 @@ module.exports = ProjectEditorHandler =
|
|||
ownerFeatures = null
|
||||
filteredMembers = []
|
||||
filteredTokenMembers = []
|
||||
for member in members
|
||||
for member in (members || [])
|
||||
if member.privilegeLevel == "owner"
|
||||
ownerFeatures = member.user.features
|
||||
owner = @buildUserModelView member.user, "owner"
|
||||
else
|
||||
filteredMembers.push @buildUserModelView member.user, member.privilegeLevel
|
||||
for tokenMember in tokenMembers
|
||||
for tokenMember in (tokenMembers || [])
|
||||
filteredTokenMembers.push @buildUserModelView tokenMember.user, tokenMember.privilegeLevel
|
||||
return {
|
||||
owner: owner,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
ProjectController = require "../Project/ProjectController"
|
||||
AuthenticationController = require '../Authentication/AuthenticationController'
|
||||
TokenAccessHandler = require './TokenAccessHandler'
|
||||
EditorRealTimeController = require "../Editor/EditorRealTimeController"
|
||||
Errors = require '../Errors/Errors'
|
||||
logger = require 'logger-sharelatex'
|
||||
|
||||
|
@ -61,6 +62,12 @@ module.exports = TokenAccessController =
|
|||
logger.err {err, token, userId, projectId: project._id},
|
||||
"error adding user to project with readAndWrite token"
|
||||
return next(err)
|
||||
setTimeout( () ->
|
||||
EditorRealTimeController.emitToRoom(
|
||||
'project:membership:changed',
|
||||
{tokenMembers: true}
|
||||
)
|
||||
, 1000)
|
||||
return TokenAccessController._loadEditor(project._id, req, res, next)
|
||||
|
||||
readOnlyToken: (req, res, next) ->
|
||||
|
@ -96,4 +103,3 @@ module.exports = TokenAccessController =
|
|||
return next(err)
|
||||
return TokenAccessController._loadEditor(project._id, req, res, next)
|
||||
|
||||
|
||||
|
|
|
@ -346,3 +346,4 @@ module.exports = class Router
|
|||
TokenAccessController.readAndWriteToken
|
||||
|
||||
webRouter.get '*', ErrorController.notFound
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ block requirejs
|
|||
window.csrfToken = "!{csrfToken}";
|
||||
window.anonymous = #{anonymous};
|
||||
window.anonymousAccessToken = "#{anonymousAccessToken}";
|
||||
window.isTokenMember = #{!!isTokenMember};
|
||||
window.maxDocLength = #{maxDocLength};
|
||||
window.trackChangesState = data.trackChangesState;
|
||||
window.showTrackChangesOnboarding = #{!!showTrackChangesOnboarding};
|
||||
|
|
|
@ -80,18 +80,15 @@
|
|||
on-toggle="toggleTrackChangesForUser(isOn, member.id);"
|
||||
disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write"
|
||||
)
|
||||
|
||||
li.rp-tc-state-separator
|
||||
li.rp-tc-state-item(
|
||||
ng-repeat="member in reviewPanel.formattedProjectTokenMembers"
|
||||
)
|
||||
span.rp-tc-state-item-name(
|
||||
ng-class="{ 'rp-tc-state-item-name-disabled' : reviewPanel.trackChangesOnForEveryone}"
|
||||
style="color: hsl({{ member.hue }}, 70%, 40%);"
|
||||
) {{ member.name }}
|
||||
li.rp-tc-state-item.rp-tc-state-item-guests
|
||||
// span.rp-tc-state-item-name !{translate("tc_guests")}
|
||||
span.rp-tc-state-item-name Guests
|
||||
review-panel-toggle(
|
||||
ng-model="reviewPanel.trackChangesState[member.id].value"
|
||||
on-toggle="toggleTrackChangesForUser(isOn, member.id);"
|
||||
disabled="reviewPanel.trackChangesOnForEveryone || !project.features.trackChanges || !permissions.write"
|
||||
ng-model="reviewPanel.trackChangesOnForGuests"
|
||||
on-toggle="toggleTrackChangesForGuests(isOn);"
|
||||
disabled="!project.features.trackChanges || !permissions.write"
|
||||
)
|
||||
|
||||
.rp-entry-list(
|
||||
|
|
|
@ -86,6 +86,7 @@ define [
|
|||
|
||||
$scope.settings = window.userSettings
|
||||
$scope.anonymous = window.anonymous
|
||||
$scope.isTokenMember = window.isTokenMember
|
||||
|
||||
$scope.chat = {}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ define [
|
|||
if @track_changes
|
||||
update.meta ?= {}
|
||||
update.meta.tc = @track_changes_id_seeds.inflight
|
||||
# console.log ">> update", @doc_id, update
|
||||
@socket.emit "applyOtUpdate", @doc_id, update, (error) =>
|
||||
return @_handleError(error) if error?
|
||||
state: "ok"
|
||||
|
|
|
@ -66,6 +66,7 @@ define [
|
|||
for annotation in @$scope.highlights or []
|
||||
do (annotation) =>
|
||||
colorScheme = ColorManager.getColorScheme(annotation.hue, @element)
|
||||
console.log ">> color", colorScheme
|
||||
if annotation.cursor?
|
||||
@labels.push {
|
||||
text: annotation.label
|
||||
|
|
|
@ -6,6 +6,8 @@ define [
|
|||
], (App, EventEmitter, ColorManager, RangesTracker) ->
|
||||
App.controller "ReviewPanelController", ($scope, $element, ide, $timeout, $http, $modal, event_tracking, localStorage) ->
|
||||
$reviewPanelEl = $element.find "#review-panel"
|
||||
# TODO: remove debug code
|
||||
window.S = $scope
|
||||
|
||||
$scope.SubViews =
|
||||
CUR_FILE : "cur_file"
|
||||
|
@ -18,6 +20,8 @@ define [
|
|||
$scope.reviewPanel =
|
||||
trackChangesState: {}
|
||||
trackChangesOnForEveryone: false
|
||||
trackChangesOnForGuests: false
|
||||
trackChangesOnForThisGuestClient: false
|
||||
entries: {}
|
||||
resolvedComments: {}
|
||||
hasEntries: false
|
||||
|
@ -32,7 +36,6 @@ define [
|
|||
resolvedThreadIds: {}
|
||||
rendererData: {}
|
||||
formattedProjectMembers: {}
|
||||
formattedProjectTokenMembers: {}
|
||||
fullTCStateCollapsed: true
|
||||
loadingThreads: false
|
||||
# All selected changes. If a aggregated change (insertion + deletion) is selection, the two ids
|
||||
|
@ -78,14 +81,6 @@ define [
|
|||
if member.privileges == "readAndWrite"
|
||||
$scope.reviewPanel.formattedProjectMembers[member._id] = formatUser(member)
|
||||
|
||||
$scope.$watch "project.tokenMembers", (tokenMembers) ->
|
||||
$scope.reviewPanel.formattedProjectTokenMembers = {}
|
||||
if $scope.project?.tokenMembers?
|
||||
for member in tokenMembers
|
||||
if member.privileges == "readAndWrite"
|
||||
if !_.find($scope.reviewPanel.formattedProjectMembers, (m) -> m.id == member._id)
|
||||
$scope.reviewPanel.formattedProjectTokenMembers[member._id] = formatUser(member)
|
||||
|
||||
$scope.commentState =
|
||||
adding: false
|
||||
content: ""
|
||||
|
@ -615,41 +610,67 @@ define [
|
|||
else if isLocal
|
||||
state.value = newValue
|
||||
state.syncState = UserTCSyncState.PENDING
|
||||
|
||||
|
||||
if userId == ide.$scope.user.id
|
||||
$scope.editor.wantTrackChanges = newValue
|
||||
$scope.editor.wantTrackChanges = newValue
|
||||
|
||||
_setEveryoneTCState = (newValue, isLocal = false) ->
|
||||
$scope.reviewPanel.trackChangesOnForEveryone = newValue
|
||||
project = $scope.project
|
||||
for member in project.members.concat(project.tokenMembers)
|
||||
for member in project.members
|
||||
_setUserTCState(member._id, newValue, isLocal)
|
||||
_setGuestsTCState(newValue, isLocal)
|
||||
_setUserTCState(project.owner._id, newValue, isLocal)
|
||||
|
||||
_setGuestsTCState = (newValue, isLocal = false) ->
|
||||
$scope.reviewPanel.trackChangesOnForGuests = newValue
|
||||
if (
|
||||
ide.$scope.project.publicAccesLevel == 'tokenBased' &&
|
||||
ide.$scope.isTokenMember &&
|
||||
ide.$scope?.user?.id?
|
||||
)
|
||||
$scope.trackChangesOnForThisGuestClient = newValue
|
||||
_setUserTCState(ide.$scope.user.id, newValue, isLocal)
|
||||
|
||||
applyClientTrackChangesStateToServer = () ->
|
||||
data = {}
|
||||
if $scope.reviewPanel.trackChangesOnForGuests
|
||||
data.on_for_guests = true
|
||||
if $scope.reviewPanel.trackChangesOnForEveryone
|
||||
data = {on : true}
|
||||
data.on = true
|
||||
else
|
||||
data = {on_for: {}}
|
||||
data.on_for = {}
|
||||
for userId, userState of $scope.reviewPanel.trackChangesState
|
||||
data.on_for[userId] = userState.value
|
||||
if !(
|
||||
$scope.reviewPanel.trackChangesOnForGuests &&
|
||||
$scope.reviewPanel.trackChangesOnForThisGuestClient
|
||||
)
|
||||
data.on_for[userId] = userState.value
|
||||
data._csrf = window.csrfToken
|
||||
$http.post "/project/#{$scope.project_id}/track_changes", data
|
||||
|
||||
applyTrackChangesStateToClient = (state) ->
|
||||
console.log ">> applying tc state to client", state
|
||||
if typeof state is "boolean"
|
||||
_setEveryoneTCState state
|
||||
_setGuestsTCState state
|
||||
else
|
||||
project = $scope.project
|
||||
$scope.reviewPanel.trackChangesOnForEveryone = false
|
||||
for member in project.members.concat(project.tokenMembers)
|
||||
_setGuestsTCState(state.__guests__ == true)
|
||||
for member in project.members
|
||||
_setUserTCState(member._id, state[member._id] ? false)
|
||||
_setUserTCState($scope.project.owner._id, state[$scope.project.owner._id] ? false)
|
||||
|
||||
|
||||
$scope.toggleTrackChangesForEveryone = (onForEveryone) ->
|
||||
_setEveryoneTCState onForEveryone, true
|
||||
_setGuestsTCState onForEveryone, true
|
||||
applyClientTrackChangesStateToServer()
|
||||
|
||||
|
||||
$scope.toggleTrackChangesForGuests = (onForGuests) ->
|
||||
_setGuestsTCState onForGuests, true
|
||||
applyClientTrackChangesStateToServer()
|
||||
|
||||
$scope.toggleTrackChangesForUser = (onForUser, userId) ->
|
||||
_setUserTCState userId, onForUser, true
|
||||
applyClientTrackChangesStateToServer()
|
||||
|
|
|
@ -39,4 +39,14 @@ define [
|
|||
$scope.project.invites = data.invites
|
||||
.catch () =>
|
||||
console.error "Error fetching invites for project"
|
||||
if data.tokenMembers
|
||||
console.log ">> token members changed"
|
||||
projectTokenMembers.getTokenMembers()
|
||||
.then (response) =>
|
||||
{ data } = response
|
||||
console.log ">> got token members", data
|
||||
if data.tokenMembers
|
||||
$scope.project.tokenMembers = data.tokenMembers
|
||||
.catch () =>
|
||||
console.error "Error fetching tokenMembers for project"
|
||||
]
|
||||
|
|
|
@ -25,5 +25,12 @@ define [
|
|||
"X-Csrf-Token": window.csrfToken
|
||||
})
|
||||
|
||||
getTokenMembers: () ->
|
||||
$http.get("/project/#{ide.project_id}/token_members", {
|
||||
json: true
|
||||
headers:
|
||||
"X-Csrf-Token": window.csrfToken
|
||||
})
|
||||
|
||||
}
|
||||
]
|
||||
|
|
|
@ -207,6 +207,9 @@
|
|||
.rp-tc-state-item-name-disabled {
|
||||
opacity: .35;
|
||||
}
|
||||
.rp-tc-state-item-guests {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
.rp-entry-list {
|
||||
display: none;
|
||||
|
|
Loading…
Reference in a new issue