Skip to content

Commit

Permalink
Merge pull request #350 from ImageMarkup/user-name
Browse files Browse the repository at this point in the history
Use obfuscated user names more comprehensively
  • Loading branch information
brianhelba authored Feb 28, 2017
2 parents 0e7eb4b + 22d70ef commit 49fa6d4
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 33 deletions.
27 changes: 18 additions & 9 deletions server/api/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,14 @@ def getStudy(self, study, params):
output.pop('creatorId'),
force=True, exc=True),
currentUser),
'users': [
User.filteredSummary(annotatorUser, currentUser)
for annotatorUser in
Study.getAnnotators(study).sort('login', SortDir.ASCENDING)
],
'users': sorted(
(
User.filteredSummary(annotatorUser, currentUser)
for annotatorUser in
Study.getAnnotators(study)
),
key=lambda annotatorUser: User.obfuscatedName(annotatorUser)
),
'images': list(
Study.getImages(
study, Image.summaryFields
Expand Down Expand Up @@ -172,8 +175,10 @@ def _getStudyCSVStream(self, study):
Study.getImages(study).sort('lowerName', SortDir.ASCENDING))

for annotatorUser, image in itertools.product(
Study.getAnnotators(study).sort('login', SortDir.ASCENDING),
images
sorted(
Study.getAnnotators(study),
key=lambda annotatorUser: User.obfuscatedName(annotatorUser)),
images
):
# this will iterate either 0 or 1 times
for annotation in Study.childAnnotations(
Expand All @@ -188,8 +193,12 @@ def _getStudyCSVStream(self, study):

filteredAnnotatorUser = User.filteredSummary(
annotatorUser, currentUser)
annotatorUserName = filteredAnnotatorUser.get(
'login', filteredAnnotatorUser['name'])
annotatorUserName = filteredAnnotatorUser['name']
if 'login' in filteredAnnotatorUser:
annotatorUserName += ' [%s %s (%s)]' % (
filteredAnnotatorUser['firstName'],
filteredAnnotatorUser['lastName'],
filteredAnnotatorUser['login'])

outDictBase = {
'study_name': study['name'],
Expand Down
6 changes: 5 additions & 1 deletion server/models/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ def addAnnotator(self, study, annotatorUser, creatorUser,
images=None):
Annotation = self.model('annotation', 'isic_archive')
Group = self.model('group')
User = self.model('user', 'isic_archive')

if not images:
images = self.getImages(study)

Expand All @@ -97,7 +99,9 @@ def addAnnotator(self, study, annotatorUser, creatorUser,

annotatorFolder = self.createFolder(
parent=study,
name='%(login)s (%(firstName)s %(lastName)s)' % annotatorUser,
name=User.obfuscatedName(annotatorUser),
# Allow a rename, in the rare event of an obfuscated name collision
allowRename=True,
description='',
parentType='folder',
# Inherit public access state from parent
Expand Down
37 changes: 19 additions & 18 deletions server/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,27 @@ def _onUserCreated(self, event):
)
self.save(user)

def obfuscatedName(self, user):
# For 4 characters of a Base32 encoding, we have 20 bits of entropy,
# or 1,048,576 possible combinations. Per the formula at
# http://preshing.com/20110504/hash-collision-probabilities/
# and assuming 100 (active) users, we have a collision probability
# of 0.47%.
obfuscatedId = base64.b32encode(
hashlib.sha256(user['login'].encode('utf8')).digest()
).decode('ascii')[:4]
obfuscatedName = 'User %s' % obfuscatedId
return obfuscatedName

def filteredSummary(self, user, accessorUser):
userSummary = {
'_id': user['_id'],
'name': self.obfuscatedName(user)
}
if self.hasAccess(user, accessorUser):
return {
field: user[field]
for field in
['_id', 'login', 'firstName', 'lastName']
}
else:
# For 4 characters of a Base32 encoding, we have 20 bits of entropy,
# or 1,048,576 possible combinations. Per the formula at
# http://preshing.com/20110504/hash-collision-probabilities/
# and assuming 100 (active) users, we have a collision probability
# of 0.47%.
obfuscatedName = base64.b32encode(
hashlib.sha256(user['login'].encode('utf8')).digest()
).decode('ascii')[:4]
return {
'_id': user['_id'],
'name': 'User %s' % obfuscatedName
}
for field in ['login', 'firstName', 'lastName']:
userSummary[field] = user[field]
return userSummary

def _isAdminOrMember(self, user, groupName):
Group = self.model('group')
Expand Down
6 changes: 5 additions & 1 deletion web_external/collections/UserCollection.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
isic.collections.UserCollection = girder.collections.UserCollection.extend({
model: isic.models.UserModel
model: isic.models.UserModel,

// ISIC Users may not always contain a 'lastName'
sortField: 'name',
secondarySortField: '_id'
});
19 changes: 15 additions & 4 deletions web_external/models/UserModel.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
isic.models.UserModel = girder.models.UserModel.extend({
name: function () {
var name;
var realName;
if (this.has('login')) {
name = this.get('firstName') + ' ' + this.get('lastName') +
realName =
this.get('firstName') +
' ' + this.get('lastName') +
' (' + this.get('login') + ')';
}

var displayName;
if (this.has('name')) {
displayName = this.get('name');
if (realName) {
displayName += ' [' + realName + ']';
}
} else {
name = this.get('name');
// The user should always have either a 'login' or a 'name'
displayName = realName;
}
return name;
return displayName;
},

canAcceptTerms: function () {
Expand Down

0 comments on commit 49fa6d4

Please sign in to comment.