Skip to content

Commit

Permalink
Initial working version of thread-based permissions
Browse files Browse the repository at this point in the history
* Users view can now be specific to a thread, not just a group
  * Link is according to current view
  * Specific views (e.g. message) link to broader views (group, global)
  * New topnav link to Exit Users and go back to message
  * Potentially multiple levels of crossing out, according to various
    levels of specificity
* Redefined "membership" to include any role, not just "read".
  (More natural.)  accessibleGroups() replaces readableGroups().
* memberOfGroup() and memberOfGroups() now include partial members
  (where some message has some role), not just full members.
* messageRoleCheck() to complement groupRoleCheck():
  check for group role or specific message role.
  Change most groupRoleCheck()s over to messageRoleCheck(),
  including canPost, canEdit, canAdmin
* accessibleMessagesQuery() and canSee() logic majorly reworked.
* New message2root helper
* Further split front page into three types of groups:
  * Groups with full membership
  * Groups with partial access
  * Groups with anonymous access
  * All other groups (for superusers only, and only with superuser "on")
* Limitations: Files and users aren't getting published to partial members.
  • Loading branch information
edemaine committed Mar 24, 2018
1 parent b6016f6 commit dfee190
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 120 deletions.
36 changes: 36 additions & 0 deletions client/frontpage.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,42 @@ Template.frontpage.events
else
console.log 'recomputeRoots done!'

groupsSort =
sort: [['name', 'asc']]

Template.frontpage.helpers
groupsAnonymous: ->
Groups.find
anonymous: $nin: [null, []]
, groupsSort

groupsMine: ->
Groups.find
name: $in: (unescapeGroup group \
for own group, roles of Meteor.user()?.roles ? {} \
when not _.isEmpty roles)
, groupsSort

groupsPartial: ->
full = {}
for own group, roles of Meteor.user()?.roles ? {}
full[group] = true if not _.isEmpty roles
Groups.find
name: $in: (unescapeGroup group \
for own group, msgs of Meteor.user()?.rolesPartial ? {} \
when group not of full and not _.isEmpty msgs)
, groupsSort

groupsOther: ->
Groups.find
name: $nin: memberOfGroups() # groupsMine plus groupsPartial
anonymous: $in: [null, []]
, groupsSort

Template.groupList.helpers
## null op to use `each` with data that's already an array
groups: -> @

Template.groupNew.events
'click .groupNewButton': (e, t) ->
e.preventDefault()
Expand Down
40 changes: 27 additions & 13 deletions client/frontpage.jade
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,39 @@ template(name="frontpage")
.alert.alert-danger(role="alert") Please <B>sign in</B> (in the upper-right corner) to get started.
else
.alert.alert-warning(role="alert") Loading...
h3
span.badge= groupsMine.count
| Groups you're a member of
with groupsMine
+groupList
if groupsPartial.count
h3
span.badge= groupsPartial.count
| Groups with partial access
with groupsPartial
+groupList
if groupsAnonymous.count
h3
span.badge= groupsAnonymous.count
| Groups with anonymous access
with groupsAnonymous
+groupList
if canSuper
h3 Your Groups
.list-group
each groupsMine
a.list-group-item(href="{{pathFor 'group' group=name}}")= name
p
i #{groupsMine.count} groups
if canSuper
h3 Other Groups
.list-group
each groupsOther
a.list-group-item(href="{{pathFor 'group' group=name}}")= name
p
i #{groupsOther.count} groups
h3
span.badge= groupsOther.count
| All other groups
with groupsOther
+groupList
.btn-group
button.btn.btn-info.groupNewButton New Group
button.btn.btn-warning.recomputeAuthorsButton Recompute Authors
button.btn.btn-warning.recomputeRootsButton Recompute Roots

template(name="groupList")
.list-group
each groups
a.list-group-item(href="{{pathFor 'group' group=name}}")= name

template(name="groupNew")
.modal
.modal-dialog.groupNew
Expand Down
19 changes: 1 addition & 18 deletions client/group.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@routeGroupRoute = ->
Router.current().params.group
Router.current()?.params?.group

@routeGroup = ->
group = routeGroupRoute()
Expand Down Expand Up @@ -46,23 +46,6 @@ Template.registerHelper 'groups', ->
Groups.find {},
sort: [['name', 'asc']]

Template.registerHelper 'groupsMine', ->
Groups.find
$or: [
name: $in: (unescapeGroup group for own group, roles of Meteor.user()?.roles ? {} when 'read' in roles)
,
anonymous: 'read'
]
,
sort: [['name', 'asc']]

Template.registerHelper 'groupsOther', ->
Groups.find
name: $nin: (unescapeGroup group for own group, roles of Meteor.user()?.roles ? {} when 'read' in roles)
anonymous: $ne: 'read'
,
sort: [['name', 'asc']]

Template.registerHelper 'admin', -> canAdmin @group ? routeGroup()

Template.registerHelper 'canImport', -> canImport @group ? routeGroup()
Expand Down
19 changes: 16 additions & 3 deletions client/layout.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@ Template.layout.helpers
'active'
else
''
showUsers: ->
Router.current().route?.getName() != 'users' and
canAdmin routeGroupOrWild()
inUsers: ->
(Router.current().route?.getName() ? '')[...5] == 'users'
linkToUsers: ->
if message = routeMessage()
pathFor 'users.message',
group: routeGroupOrWild()
message: message2root message
else
pathFor 'users', group: routeGroupOrWild()
linkToUsersExit: ->
if message = routeMessage()
pathFor 'message',
group: routeGroupOrWild()
message: message
else
pathFor 'group', group: routeGroupOrWild()
linkToGroup: ->
router = Router.current()
route = Router.current().route?.getName()
Expand Down
7 changes: 5 additions & 2 deletions client/layout.jade
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ template(name="layout")
button.superButton.btn.btn-normal Leave Superuser
else
button.superButton.btn.btn-danger Become Superuser
if showUsers
a.btn.btn-warning(href="{{pathFor 'users' data=routeGroupOrWildData}}") Users
if admin
if inUsers
a.btn.btn-success(href="{{linkToUsersExit}}") Exit Users
else
a.btn.btn-warning(href="{{linkToUsers}}") Users
if currentUser
a.btn.btn-default(href="{{pathFor 'settings' data=routeGroupOrWildData}}") Settings
ul.nav.navbar-nav.navbar-right
Expand Down
3 changes: 3 additions & 0 deletions client/message.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ switch sharejsEditor
#$(e.target).parent().dropdown 'toggle'
$(e.target).parents('.dropdown-menu').first().parent().find('.dropdown-toggle').dropdown 'toggle'

@routeMessage = ->
Router.current()?.params?.message

#Template.registerHelper 'titleOrUntitled', ->
# titleOrUntitled @

Expand Down
47 changes: 26 additions & 21 deletions client/users.coffee
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
haveRole = (role, roles) ->
haveRole = (role, profile) ->
group = routeGroup()
if role in (roles?[escapeGroup group] ? [])
message = routeMessage()
levels = []
if message
have = role in (profile.rolesPartial?[escapeGroup group]?[message] ? [])
else
have = role in (profile.roles?[escapeGroup group] ? [])
if have
btnclass = 'success'
local = 'YES'
levels.push 'YES'
else
btnclass = 'danger'
local = 'NO'
global = ''
if group != wildGroup
if role in (roles?[wildGroup] ? [])
local = "<del>#{local}</del>"
global = ' <b class="text-success space">YES*</b>'
#else
# global = 'NO*'
levels.push 'NO'
if message and role in (profile.roles?[escapeGroup group] ? [])
levels.push "<del>#{levels.pop()}</del>"
levels.push '<b class="text-success space">YES</b>'
if group != wildGroup and role in (profile.roles?[wildGroup] ? [])
levels.push "<del>#{levels.pop()}</del>"
levels.push '<b class="text-success space">YES*</b>'
if groupRoleCheck group, 'admin'
local = "<button class='roleButton btn btn-#{btnclass}'>#{local}</button>"
local + global
levels[0] = "<button class='roleButton btn btn-#{btnclass}'>#{levels[0]}</button>"
levels.join ' '

anonRole = (role, group) ->
roles = groupAnonymousRoles group
Expand All @@ -37,7 +42,7 @@ Template.users.helpers
users: ->
Meteor.users.find {},
sort: [['createdAt', 'asc']]
fullname: -> @profile.fullname
fullname: -> @profile?.fullname
email: ->
email = @emails?[0]
unless email
Expand All @@ -55,11 +60,11 @@ Template.users.helpers
name: @group
?.invitations ? []

readRole: -> haveRole 'read', @roles
postRole: -> haveRole 'post', @roles
editRole: -> haveRole 'edit', @roles
superRole: -> haveRole 'super', @roles
adminRole: -> haveRole 'admin', @roles
readRole: -> haveRole 'read', @
postRole: -> haveRole 'post', @
editRole: -> haveRole 'edit', @
superRole: -> haveRole 'super', @
adminRole: -> haveRole 'admin', @

anonReadRole: -> anonRole 'read', @group
anonPostRole: -> anonRole 'post', @group
Expand All @@ -82,9 +87,9 @@ Template.users.events
role = td.getAttribute 'data-role'
old = e.target.innerHTML
if 0 <= old.indexOf 'YES'
Meteor.call 'setRole', t.data.group, username, role, false
Meteor.call 'setRole', t.data.group, t.data.message, username, role, false
else if 0 <= old.indexOf 'NO'
Meteor.call 'setRole', t.data.group, username, role, true
Meteor.call 'setRole', t.data.group, t.data.message, username, role, true

'click .invitationButton': (e, t) ->
console.log t.find('#invitationInput').value
Expand Down
19 changes: 14 additions & 5 deletions client/users.jade
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
template(name="users")
table.table.table-striped.table-hover.users
h3
if message
| Permissions for thread &ldquo;<a href="{{pathFor 'message' group=group message=message}}">#{message}</a>&rdquo; in group &ldquo;<a href="{{pathFor 'group' group=group}}">#{group}</a>&rdquo;
else
if wildLink
| Permissions for group &ldquo;<a href="{{pathFor 'group' group=group}}">#{group}</a>&rdquo;
else
| Global permissions for all groups
.links.btn-group.pull-right
if message
a(href="{{pathFor 'users' group=group}}").btn.btn-warning Edit Group Permissions
if wildLink
a(href=wildHref).btn.btn-danger Edit Global Permissions
table.table.table-striped.table-hover.users.clearfix
thead
tr
th Username
Expand Down Expand Up @@ -36,10 +49,6 @@ template(name="users")
td(data-role="edit") !{anonEditRole}
td(data-role="super") !{anonSuperRole}
td(data-role="admin") !{anonAdminRole}
if wildLink
tr
td(colspan='6')
a(href=wildHref).btn.btn-warning Edit Global User Permissions
if showInvitations
tr
td(colspan='6')
Expand Down
8 changes: 4 additions & 4 deletions lib/files.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@ if Meteor.isServer
'metadata._Resumable': $exists: false
#$or:
# 'metadata.updator': @userId
'metadata.group': $in: readableGroupNames userid
'metadata.group': $in: accessibleGroupNames userid

Meteor.publish 'files', (group) ->
check group, String
@autorun ->
if groupRoleCheck group, 'read', findUser @userId
if memberOfGroup group, findUser @userId
Files.find
'metadata._Resumable': $exists: false
'metadata.group': group
Expand All @@ -121,12 +121,12 @@ if Meteor.isServer
check file.metadata,
group: Match.Optional String
file.metadata.uploader = userId
groupRoleCheck file.metadata.group ? wildGroup, 'post', findUser userId
memberOfGroup file.metadata.group ? wildGroup, findUser userId
remove: (userId, file) ->
file.metadata?.uploader in [userId, null]
read: (userId, file) ->
file.metadata?.uploader in [userId, null] or
groupRoleCheck file.metadata?.group, 'read', findUser userId
memberOfGroup file.metadata?.group, findUser userId
write: (userId, file, fields) ->
file.metadata?.uploader in [userId, null]
else
Expand Down
Loading

0 comments on commit dfee190

Please sign in to comment.