Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added adminRole property and functionality #231

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ AdminConfig = {
}
};
```

By default, the `"admin"` role will be used to identify administrators. To identify administrators by another role, you can use the `adminRole` property:

```javascript
AdminConfig = {
name: 'My App',
adminRole: 'Owner',
collections: {
Posts: {}
}
};
```

#### 3. Define your data models ####
If you are unfamiliar with [autoform](https://github.com/aldeed/meteor-autoform) or [collection2](https://github.com/aldeed/meteor-collection2) or [collection-helpers](https://github.com/dburles/meteor-collection-helpers) you should check them out now.

Expand Down
2 changes: 1 addition & 1 deletion lib/both/AdminDashboard.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ AdminDashboard =
Session.set 'adminError', message

checkAdmin: ->
if not Roles.userIsInRole Meteor.userId(), ['admin']
if not Roles.userIsInRole Meteor.userId(), [AdminConfig?.adminRole or 'admin']
Meteor.call 'adminCheckAdmin'
if (typeof AdminConfig?.nonAdminRedirectRoute == "string")
Router.go AdminConfig.nonAdminRedirectRoute
Expand Down
6 changes: 3 additions & 3 deletions lib/both/router.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
layoutTemplate: 'AdminLayout'
waitOn: ->
[
Meteor.subscribe 'adminUsers'
Meteor.subscribe 'adminUser'
Meteor.subscribe 'adminCollectionsCount'
]
onBeforeAction: ->
Session.set 'adminSuccess', null
Expand All @@ -17,7 +15,7 @@
Session.set 'admin_id', null
Session.set 'admin_doc', null

if not Roles.userIsInRole Meteor.userId(), ['admin']
if not Roles.userIsInRole Meteor.userId(), [AdminConfig?.adminRole or 'admin']
Meteor.call 'adminCheckAdmin'
if typeof AdminConfig?.nonAdminRedirectRoute == 'string'
Router.go AdminConfig.nonAdminRedirectRoute
Expand Down Expand Up @@ -69,6 +67,8 @@ Router.route "adminDashboardUsersEdit",
user: Meteor.users.find(@params._id).fetch()
roles: Roles.getRolesForUser @params._id
otherRoles: _.difference _.map(Meteor.roles.find().fetch(), (role) -> role.name), Roles.getRolesForUser(@params._id)
waitOn: ->
Meteor.subscribe 'adminCollectionDoc', 'Meteor.users', parseID(@params._id)
action: ->
@render()
onAfterAction: ->
Expand Down
14 changes: 8 additions & 6 deletions lib/both/startup.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ adminEditButton = {
data: '_id'
title: 'Edit'
createdCell: (node, cellData, rowData) ->
$(node).html(Blaze.toHTMLWithData Template.adminEditBtn, {_id: cellData}, node)
$(node).html(Blaze.toHTMLWithData Template.adminEditBtn, {_id: cellData})
width: '40px'
orderable: false
}
adminDelButton = {
data: '_id'
title: 'Delete'
createdCell: (node, cellData, rowData) ->
$(node).html(Blaze.toHTMLWithData Template.adminDeleteBtn, {_id: cellData}, node)
$(node).html(Blaze.toHTMLWithData Template.adminDeleteBtn, {_id: cellData})
width: '40px'
orderable: false
}
Expand Down Expand Up @@ -48,28 +48,30 @@ AdminTables.Users = new Tabular.Table
title: 'Admin'
# TODO: use `tmpl`
createdCell: (node, cellData, rowData) ->
$(node).html(Blaze.toHTMLWithData Template.adminUsersIsAdmin, {_id: cellData}, node)
$(node).html(Blaze.toHTMLWithData Template.adminUsersIsAdmin, {_id: cellData})
width: '40px'
}
{
data: 'emails'
title: 'Email'
render: (value) ->
value[0].address
value?[0]?.address
searchable: true
}
{
data: 'emails'
title: 'Mail'
# TODO: use `tmpl`
createdCell: (node, cellData, rowData) ->
$(node).html(Blaze.toHTMLWithData Template.adminUsersMailBtn, {emails: cellData}, node)
$(node).html(Blaze.toHTMLWithData Template.adminUsersMailBtn, {emails: cellData})
width: '40px'
}
{ data: 'createdAt', title: 'Joined' }
], adminEditDelButtons
dom: adminTablesDom

adminCollectionObject['Meteor.users'] = Meteor.users

adminTablePubName = (collection) ->
"admin_tabular_#{collection}"

Expand All @@ -84,7 +86,7 @@ adminCreateTables = (collections) ->
if column.template
createdCell = (node, cellData, rowData) ->
$(node).html ''
Blaze.renderWithData(Template[column.template], {value: cellData, doc: rowData}, node)
Blaze.renderWithData(Template[column.template], {value: cellData, doc: rowData})

data: column.name
title: column.label
Expand Down
2 changes: 1 addition & 1 deletion lib/client/html/admin_layouts.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template name="AdminLayout">
{{#if AdminConfig}}
{{#if isInRole 'admin'}}
{{#if isInRole adminRole}}
<div class="admin-layout">
{{#AdminLTE}}
{{> AdminHeader}}
Expand Down
2 changes: 1 addition & 1 deletion lib/client/html/admin_templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ <h4>Change Password</h4>
</template>

<template name="adminUsersIsAdmin">
{{#if adminIsUserInRole this._id 'admin'}}<i class="fa fa-check"></i>{{/if}}
{{#if adminIsUserInRole this._id adminRole}}<i class="fa fa-check"></i>{{/if}}
</template>

<template name="adminUsersMailBtn">
Expand Down
3 changes: 0 additions & 3 deletions lib/client/html/admin_widgets.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
<a href="/admin/{{this.name}}">
<div class="small-box bg-{{color}}">
<div class="inner">
<h3>
{{adminCollectionCount name}}
</h3>
<p>
{{this.label}}
</p>
Expand Down
4 changes: 2 additions & 2 deletions lib/client/js/autoForm.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ AutoForm.hooks
hook = @
Meteor.call 'adminInsertDoc', insertDoc, Session.get('admin_collection_name'), (e,r)->
if e
hook.done(e)
alert(e?.message || e); hook.done(e)
else
adminCallback 'onInsert', [Session.get 'admin_collection_name', insertDoc, updateDoc, currentDoc], (collection) ->
hook.done null, collection
Expand All @@ -33,7 +33,7 @@ AutoForm.hooks
hook = @
Meteor.call 'adminUpdateDoc', updateDoc, Session.get('admin_collection_name'), Session.get('admin_id'), (e,r)->
if e
hook.done(e)
alert(e?.message || e); hook.done(e)
else
adminCallback 'onUpdate', [Session.get 'admin_collection_name', insertDoc, updateDoc, currentDoc], (collection) ->
hook.done null, collection
Expand Down
8 changes: 4 additions & 4 deletions lib/client/js/helpers.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ adminCollections = ->
UI.registerHelper 'AdminConfig', ->
AdminConfig if typeof AdminConfig != 'undefined'

UI.registerHelper 'adminRole', ->
AdminConfig?.adminRole or 'admin'

UI.registerHelper 'admin_skin', ->
AdminConfig?.skin or 'blue'

Expand Down Expand Up @@ -88,10 +91,7 @@ UI.registerHelper 'adminCollectionLabel', (collection)->
AdminDashboard.collectionLabel(collection) if collection?

UI.registerHelper 'adminCollectionCount', (collection)->
if collection == 'Users'
Meteor.users.find().count()
else
AdminCollectionsCount.findOne({collection: collection})?.count
AdminCollectionsCount.findOne({collection: collection})?.count

UI.registerHelper 'adminTemplate', (collection, mode)->
if collection?.toLowerCase() != 'users' && typeof AdminConfig?.collections?[collection]?.templates != 'undefined'
Expand Down
2 changes: 1 addition & 1 deletion lib/client/js/templates.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Template.AdminDashboardView.rendered = ->

Template.AdminDashboardView.helpers
hasDocuments: ->
AdminCollectionsCount.findOne({collection: Session.get 'admin_collection_name'})?.count > 0
return true
newPath: ->
Router.path 'adminDashboard' + Session.get('admin_collection_name') + 'New'

Expand Down
47 changes: 17 additions & 30 deletions lib/server/methods.coffee
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
Meteor.methods
adminInsertDoc: (doc,collection)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
Future = Npm.require('fibers/future');
fut = new Future();

adminCollectionObject(collection).insert doc, (e,_id)->
fut['return']( {e:e,_id:_id} )
return fut.wait()
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
return adminCollectionObject(collection).insert doc

adminUpdateDoc: (modifier,collection,_id)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
Future = Npm.require('fibers/future');
fut = new Future();
adminCollectionObject(collection).update {_id:_id},modifier,(e,r)->
fut['return']( {e:e,r:r} )
return fut.wait()
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
return adminCollectionObject(collection).update {_id:_id},modifier

adminRemoveDoc: (collection,_id)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
if collection == 'Users'
Meteor.users.remove {_id:_id}
else
Expand All @@ -30,7 +21,7 @@ Meteor.methods

adminNewUser: (doc) ->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
emails = doc.email.split(',')
_.each emails, (email)->
user = {}
Expand All @@ -52,54 +43,50 @@ Meteor.methods

adminUpdateUser: (modifier,_id)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
Future = Npm.require('fibers/future');
fut = new Future();
Meteor.users.update {_id:_id},modifier,(e,r)->
fut['return']( {e:e,r:r} )
return fut.wait()
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
Meteor.users.update {_id:_id},modifier

adminSendResetPasswordEmail: (doc)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
console.log 'Changing password for user ' + doc._id
Accounts.sendResetPasswordEmail(doc._id)

adminChangePassword: (doc)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
console.log 'Changing password for user ' + doc._id
Accounts.setPassword(doc._id, doc.password)
label: 'Email user their new password'

adminCheckAdmin: ->
check arguments, [Match.Any]
user = Meteor.users.findOne(_id:this.userId)
if this.userId and !Roles.userIsInRole(this.userId, ['admin']) and (user.emails.length > 0)
if this.userId and !Roles.userIsInRole(this.userId, [AdminConfig?.adminRole or 'admin']) and (user.emails.length > 0)
email = user.emails[0].address
if typeof Meteor.settings.adminEmails != 'undefined'
adminEmails = Meteor.settings.adminEmails
if adminEmails.indexOf(email) > -1
console.log 'Adding admin user: ' + email
Roles.addUsersToRoles this.userId, ['admin'], Roles.GLOBAL_GROUP
Roles.addUsersToRoles this.userId, [AdminConfig?.adminRole or 'admin'], Roles.GLOBAL_GROUP
else if typeof AdminConfig != 'undefined' and typeof AdminConfig.adminEmails == 'object'
adminEmails = AdminConfig.adminEmails
if adminEmails.indexOf(email) > -1
console.log 'Adding admin user: ' + email
Roles.addUsersToRoles this.userId, ['admin'], Roles.GLOBAL_GROUP
Roles.addUsersToRoles this.userId, [AdminConfig?.adminRole or 'admin'], Roles.GLOBAL_GROUP
else if this.userId == Meteor.users.findOne({},{sort:{createdAt:1}})._id
console.log 'Making first user admin: ' + email
Roles.addUsersToRoles this.userId, ['admin']
Roles.addUsersToRoles this.userId, [AdminConfig?.adminRole or 'admin']

adminAddUserToRole: (_id,role)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
Roles.addUsersToRoles _id, role, Roles.GLOBAL_GROUP

adminRemoveUserToRole: (_id,role)->
check arguments, [Match.Any]
if Roles.userIsInRole this.userId, ['admin']
Roles.removeUsersFromRoles _id, role
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
Roles.removeUsersFromRoles _id, role, Roles.GLOBAL_GROUP

adminSetCollectionSort: (collection, _sort) ->
check arguments, [Match.Any]
Expand Down
28 changes: 2 additions & 26 deletions lib/server/publish.coffee
Original file line number Diff line number Diff line change
@@ -1,45 +1,21 @@
Meteor.publishComposite 'adminCollectionDoc', (collection, id) ->
check collection, String
check id, Match.OneOf(String, Mongo.ObjectID)
if Roles.userIsInRole this.userId, ['admin']
if Roles.userIsInRole this.userId, [AdminConfig?.adminRole or 'admin']
find: ->
adminCollectionObject(collection).find(id)
children: AdminConfig?.collections?[collection]?.children or []
else
@ready()

Meteor.publish 'adminUsers', ->
if Roles.userIsInRole @userId, ['admin']
if Roles.userIsInRole @userId, [AdminConfig?.adminRole or 'admin']
Meteor.users.find()
else
@ready()

Meteor.publish 'adminUser', ->
Meteor.users.find @userId

Meteor.publish 'adminCollectionsCount', ->
handles = []
self = @

_.each AdminTables, (table, name) ->
id = new Mongo.ObjectID
count = 0

ready = false
handles.push table.collection.find().observeChanges
added: ->
count += 1
ready and self.changed 'adminCollectionsCount', id, {count: count}
removed: ->
count -= 1
ready and self.changed 'adminCollectionsCount', id, {count: count}
ready = true

self.added 'adminCollectionsCount', id, {collection: name, count: count}

self.onStop ->
_.each handles, (handle) -> handle.stop()
self.ready()

Meteor.publish null, ->
Meteor.roles.find({})
2 changes: 0 additions & 2 deletions package.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ Package.on_use(function(api){

both = ['client','server']

api.versionsFrom('[email protected]');

api.use(
['iron:[email protected]',
'coffeescript',
Expand Down