Skip to content

Commit

Permalink
Merge pull request #451 from RocketChat/settings-users
Browse files Browse the repository at this point in the history
Settings users
  • Loading branch information
marceloschmidt committed Aug 12, 2015
2 parents 2cd1b0e + f17cc08 commit d0aa32f
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 3 deletions.
4 changes: 4 additions & 0 deletions client/methods/setUserActiveStatus.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Meteor.methods
setUserActiveStatus: (userId, active) ->
Meteor.users.update userId, { $set: { active: active } }
return true
6 changes: 6 additions & 0 deletions client/routes/router.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ FlowRouter.route '/changeavatar',
action: ->
BlazeLayout.render 'main', {center: 'avatarPrompt'}

FlowRouter.route '/settings/users',
name: 'settings-users'

action: ->
BlazeLayout.render 'main', {center: 'settingsUsers'}

FlowRouter.route '/settings/:group?',
name: 'settings'

Expand Down
45 changes: 45 additions & 0 deletions client/stylesheets/base.less
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,30 @@ blockquote {
top: 10px;
font-weight: 400;
}
.icon-spin4 {
position: absolute;
color: @secondary-font-color;
right: 5px;
top: 10px;
font-weight: 400;
-webkit-animation-name: spin;
-webkit-animation-duration: 2000ms;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-moz-animation-name: spin;
-moz-animation-duration: 2000ms;
-moz-animation-iteration-count: infinite;
-moz-animation-timing-function: linear;
-ms-animation-name: spin;
-ms-animation-duration: 2000ms;
-ms-animation-iteration-count: infinite;
-ms-animation-timing-function: linear;

animation-name: spin;
animation-duration: 2000ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
input {
padding-left: 25px;
}
Expand Down Expand Up @@ -256,6 +280,27 @@ blockquote {
}
}

@-ms-keyframes spin {
from { -ms-transform: rotate(0deg); }
to { -ms-transform: rotate(360deg); }
}
@-moz-keyframes spin {
from { -moz-transform: rotate(0deg); }
to { -moz-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
from { -webkit-transform: rotate(0deg); }
to { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
from {
transform:rotate(0deg);
}
to {
transform:rotate(360deg);
}
}

.rocket-h2 {
font-weight: 300;
text-transform: uppercase;
Expand Down
2 changes: 0 additions & 2 deletions client/views/settings/settings.coffee
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Template.settings.helpers
isAdmin: ->
return Meteor.user().admin is true
groups: ->
return Settings.find({type: 'group'}).fetch()
group: ->
group = FlowRouter.getParam('group')
group ?= Settings.findOne({ type: 'group' })?._id
Expand Down
2 changes: 1 addition & 1 deletion client/views/settings/settingsFlex.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Template.settingsFlex.helpers
groups: ->
return Settings.find({type: 'group'}).fetch()
return Settings.find({type: 'group'}, { sort: { sort: 1, i18nLabel: 1 } }).fetch()
label: ->
return TAPi18next.t @i18nLabel

Expand Down
3 changes: 3 additions & 0 deletions client/views/settings/settingsFlex.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ <h4>{{_ "Settings"}}</h4>
<a href="{{pathFor 'settings' group=_id}}">{{_ i18nLabel}}</a>
</li>
{{/each}}
<li>
<a href="{{pathFor 'settings-users'}}">{{_ "Users"}}</a>
</li>
</ul>
</div>
</div>
Expand Down
114 changes: 114 additions & 0 deletions client/views/settings/settingsUsers.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
Template.settingsUsers.helpers
isAdmin: ->
return Meteor.user().admin is true
isReady: ->
return Template.instance().ready?.get()
users: ->
filter = _.trim Template.instance().filter?.get()
if filter
filterReg = new RegExp filter, "i"
query = { $or: [ { username: filterReg }, { name: filterReg }, { "emails.address": filterReg } ] }
else
query = {}
return Meteor.users.find(query, { limit: Template.instance().limit?.get(), sort: { username: 1 } }).fetch()
name: ->
return if @name then @name else TAPi18next.t 'project:Unnamed'
email: ->
return @emails?[0]?.address
flexOpened: ->
return 'opened' if Session.equals('flexOpened', true)
arrowPosition: ->
return 'left' unless Session.equals('flexOpened', true)
userData: ->
return Meteor.users.findOne Session.get 'settingsUsersSelected'
phoneNumber: ->
return '' unless @phoneNumber
if @phoneNumber.length > 10
return "(#{@phoneNumber.substr(0,2)}) #{@phoneNumber.substr(2,5)}-#{@phoneNumber.substr(7)}"
else
return "(#{@phoneNumber.substr(0,2)}) #{@phoneNumber.substr(2,4)}-#{@phoneNumber.substr(6)}"
lastLogin: ->
if @lastLogin
return moment(@lastLogin).format('LLL')
utcOffset: ->
if @utcOffset?
if @utcOffset > 0
@utcOffset = "+#{@utcOffset}"

return "UTC #{@utcOffset}"

Template.settingsUsers.onCreated ->
instance = @
@limit = new ReactiveVar 50
@filter = new ReactiveVar ''
@ready = new ReactiveVar true

@autorun ->
filter = instance.filter.get()
limit = instance.limit.get()
subscription = instance.subscribe 'fullUsers', filter, limit
instance.ready.set subscription.ready()

Template.settingsUsers.onRendered ->
Tracker.afterFlush ->
SideNav.setFlex "settingsFlex"
SideNav.openFlex()

Template.settingsUsers.events
'keydown #users-filter': (e) ->
if e.which is 13
e.stopPropagation()
e.preventDefault()

'keyup #users-filter': (e, t) ->
e.stopPropagation()
e.preventDefault()
t.filter.set e.currentTarget.value

'click .flex-tab .more': ->
if (Session.get('flexOpened'))
Session.set('flexOpened',false)
else
Session.set('flexOpened', true)

'click .user-info': (e) ->
e.preventDefault()
Session.set 'settingsUsersSelected', $(e.currentTarget).data('id')
Session.set 'flexOpened', true

'click .deactivate': ->
Meteor.call 'setUserActiveStatus', Session.get('settingsUsersSelected'), false, (error, result) ->
if result
toastr.success t('User_has_been_deactivated')
if error
toastr.error error.reason

'click .activate': ->
Meteor.call 'setUserActiveStatus', Session.get('settingsUsersSelected'), true, (error, result) ->
if result
toastr.success t('User_has_been_activated')
if error
toastr.error error.reason

'click .delete': ->
swal {
title: t('Are_you_sure')
text: t('Delete_User_Warning')
type: 'warning'
showCancelButton: true
confirmButtonColor: '#DD6B55'
confirmButtonText: t('Yes_delete_it')
cancelButtonText: t('Cancel')
closeOnConfirm: false
html: false
}, ->
swal
title: t('Deleted')
text: t('User_has_been_deleted')
type: 'success'
timer: 2000
showConfirmButton: false

Meteor.call 'deleteUser', Session.get('settingsUsersSelected'), (error, result) ->
if error
toastr.error error.reason
80 changes: 80 additions & 0 deletions client/views/settings/settingsUsers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<template name="settingsUsers">
<section class="page-container page-list">
<head class="fixed-title">
{{> burger}}
<h2>
<span class="room-title">{{_ "Users"}}</span>
</h2>
</head>
<div class="content">
{{#unless isAdmin}}
<p>You are not authorized to view this page.</p>
{{else}}
<form class="search-form" role="form">
<div class="input-line search">
<input type="text" id="users-filter" placeholder="{{_ "Search"}}" dir="auto">
<i class="icon-search"></i>
{{#unless isReady}}<i class="icon-spin4"></i>{{/unless}}
</div>
</form>
{{#if isReady}}
<div class="results">
{{{_ "Showing_results" users.length}}}
</div>
<div class="list">
{{#each users}}
<div class="user-info" data-id="{{_id}}">
<li class='user-image status-{{status}}'>
{{> avatar username=username}}
<h3>{{name}}</h3>
</li>
<ul>
<li>@{{username}}</li>
{{#if email}}<li>{{email}}</li>{{/if}}
</ul>
</div>
{{/each}}
</div>
{{else}}
<div class="results">
{{{_ "Loading..."}}}
</div>
{{/if}}
{{/unless}}
</div>
</section>
<section class="flex-tab">
<div class="control">
<button class="more"><span class="arrow {{arrowPosition}}"></span></button>
</div>
{{#if flexOpened}}
<div class="content">
<div class="user-view">
{{#with userData}}
<div class="about clearfix">
<div class="thumb">
{{> avatar username=username}}
</div>
<div class="info">
<h3>{{name}}</h3>
<p><i class="icon-at"></i> {{username}}</p>
{{#if utcOffset}}<p><i class="icon-location"></i> {{utcOffset}}</p>{{/if}}
{{#each emails}} <p><i class="icon-mail"></i> {{address}}{{#if verified}}&nbsp;<i class="icon-ok"></i>{{/if}}</p> {{/each}}
{{#each phone}} <p><i class="icon-phone"></i> {{phoneNumber}}</p> {{/each}}
{{#if lastLogin}} <p><i class="icon-clock"></i> {{_ "Last_seen"}}: {{lastLogin}}</p> {{/if}}
</div>
</div>
<nav>
{{#if active}}
<button class='button deactivate'><span><i class='icon-block'></i> {{_ "Deactivate"}}</span></button>
{{else}}
<button class='button activate'><span><i class='icon-ok-circled'></i> {{_ "Activate"}}</span></button>
{{/if}}
<button class='button delete red'><span><i class='icon-trash'></i> {{_ "Delete"}}</span></button>
</nav>
{{/with}}
</div>
</div>
{{/if}}
</section>
</template>
3 changes: 3 additions & 0 deletions i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@
"Language" : "Language",
"Language_Version" : "English Version",
"Last_message" : "Last message",
"Last_seen" : "Last seen",
"Leave_room" : "Leave room",
"line" : "line",
"Load_more" : "Load more",
"Loading..." : "Loading...",
"Loading_suggestion" : "Loading suggestions...",
"Login" : "Login",
"Login_with" : "Login with %s",
Expand Down Expand Up @@ -181,6 +183,7 @@
"Submit" : "Submit",
"The_field_is_required" : "The field %s is required.",
"True" : "True",
"Unnamed" : "Unnamed",
"Use_initials_avatar" : "Use your username initials",
"use_menu" : "Use the side menu to access your rooms and chats",
"Use_service_avatar" : "Use %s avatar",
Expand Down
4 changes: 4 additions & 0 deletions server/lib/accounts.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Accounts.validateLoginAttempt (login) ->
if login.allowed isnt true
return login.allowed

if login.user?.active isnt true
throw new Meteor.Error 'inactive-user', 'Your_user_has_been_deactivated'
return false

if login.type is 'password' and RocketChat.settings.get 'Accounts_denyUnverifiedEmails' is true
validEmail = login.user.emails.filter (email) ->
return email.verified is true
Expand Down
11 changes: 11 additions & 0 deletions server/methods/deleteUser.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Meteor.methods
deleteUser: (userId) ->
if not Meteor.userId()
throw new Meteor.Error('invalid-user', "[methods] deleteUser -> Invalid user")

user = Meteor.users.findOne Meteor.userId()
unless user?.admin is true
throw new Meteor.Error 'not-authorized', '[methods] deleteUser -> Not authorized'

return true
# Meteor.users.remove userId
15 changes: 15 additions & 0 deletions server/methods/setUserActiveStatus.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Meteor.methods
setUserActiveStatus: (userId, active) ->
if not Meteor.userId()
throw new Meteor.Error 'invalid-user', '[methods] setUserActiveStatus -> Invalid user'

user = Meteor.users.findOne Meteor.userId()
unless user?.admin is true
throw new Meteor.Error 'not-authorized', '[methods] setUserActiveStatus -> Not authorized'

Meteor.users.update userId, { $set: { active: active } }

if active is false
Meteor.users.update userId, { $set: { "services.resume.loginTokens" : [] } }

return true
Loading

0 comments on commit d0aa32f

Please sign in to comment.