Merge branch 'master' into cron

pull/643/head
Marcelo Schmidt 11 years ago
commit c3d268461d
  1. 2
      client/lib/RoomManager.coffee
  2. 4
      client/lib/chatMessages.coffee
  3. 76
      client/lib/readMessages.coffee
  4. 8
      client/lib/readMessagesOnFocus.coffee
  5. 16
      client/routes/roomRoute.coffee
  6. 13
      client/startup/unread.coffee
  7. 82
      client/stylesheets/base.less
  8. 2
      client/stylesheets/global/_variables.less
  9. 4
      client/views/admin/adminStatistics.html
  10. 14
      client/views/admin/users/adminUserInfo.html
  11. 12
      client/views/admin/users/adminUsers.coffee
  12. 20
      client/views/app/messagePopup.coffee
  13. 1
      client/views/app/messagePopupConfig.coffee
  14. 49
      client/views/app/room.coffee
  15. 81
      client/views/app/room.html
  16. 60
      client/views/app/userInfo.coffee
  17. 75
      client/views/app/userInfo.html
  18. 3
      client/views/main.coffee
  19. 4
      i18n/en.i18n.json
  20. 2
      mobile-config.js
  21. 3
      packages/rocketchat-lib/server/functions/getStatistics.coffee
  22. 3
      packages/rocketchat-lib/settings/server/startup.coffee
  23. 44
      server/publications/fullUserData.coffee
  24. 37
      server/publications/fullUsers.coffee
  25. 1
      server/startup/indexes.coffee
  26. 6
      server/startup/migrations/v16.coffee
  27. 6
      server/startup/migrations/v17.coffee

@ -84,7 +84,7 @@ Meteor.startup ->
if type in ['c', 'p']
query.name = name
else if type is 'd'
query.usernames = $all: [Meteor.user().username, name]
query.usernames = $all: [Meteor.user()?.username, name]
room = ChatRoom.findOne query, { reactive: false }

@ -70,6 +70,10 @@ class @ChatMessages
send: (rid, input) ->
if _.trim(input.value) isnt ''
readMessage.enable()
readMessage.readNow()
$('.message.first-unread').removeClass('first-unread')
if this.editing.id
this.update(this.editing.id, rid, input)
return

@ -0,0 +1,76 @@
### DEFINITIONS
- If window loses focus user needs to scroll or click/touch some place
- On hit ESC enable read, force read of current room and remove unread mark
- When user change room disable read until user interaction
- Only read if mark of *first-unread* is visible for user or if flag *force* was passed
- Always read the opened room
- The default method *read* has a delay of 2000ms to prevent multiple reads and to user be able to see the mark
###
@readMessage = new class
constructor: ->
@canReadMessage = false
readNow: (force=false) ->
return if @canReadMessage is false
rid = Session.get 'openedRoom'
if rid?
subscription = ChatSubscription.findOne rid: rid
if subscription? and (subscription.alert is true or subscription.unread > 0)
# Only read messages if user saw the first unread message
position = $('.message.first-unread').position()
if force is true or not position? or position.top >= 0
Meteor.call 'readMessages', rid
read: _.debounce (force) ->
@readNow(force)
, 2000
disable: ->
@canReadMessage = false
enable: ->
@canReadMessage = document.hasFocus()
isEnable: ->
return @canReadMessage is true
refreshUnreadMark: (rid) ->
rid ?= Session.get 'openedRoom'
if rid?
subscription = ChatSubscription.findOne rid: rid
room = RoomManager.openedRooms[subscription.t + subscription.name]
if room?
$roomDom = $(room.dom)
$roomDom.find('.message.first-unread').addClass('first-unread-opaque')
if (subscription.rid isnt rid or readMessage.isEnable() is false) and (subscription.alert or subscription.unread > 0)
$roomDom.find('.message.first-unread').removeClass('first-unread').removeClass('first-unread-opaque')
firstUnreadId = ChatMessage.findOne({rid: subscription.rid, ts: {$gt: subscription.ls}, 'u._id': {$ne: Meteor.userId()}}, {sort: {ts: 1}})?._id
if firstUnreadId?
$roomDom.find('.message#'+firstUnreadId).addClass('first-unread')
Meteor.startup ->
$(window).on 'blur', ->
readMessage.disable()
$(window).on 'focus', ->
readMessage.enable()
readMessage.read()
$(window).on 'click', (e) ->
readMessage.enable()
readMessage.read()
$(window).on 'touchend', (e) ->
readMessage.enable()
readMessage.read()
$(window).on 'keyup', (e) ->
key = event.which
if key is 27
readMessage.enable()
readMessage.readNow(true)
$('.message.first-unread').removeClass('first-unread')

@ -1,8 +0,0 @@
Meteor.startup ->
$(window).on 'focus', ->
if FlowRouter.getRouteName() in ['channel', 'group', 'direct']
rid = Session.get 'openedRoom'
if rid?
subscription = ChatSubscription.findOne rid: rid
if subscription? and (subscription.alert is true or subscription.unread > 0)
Meteor.call 'readMessages', rid

@ -37,7 +37,12 @@ openRoom = (type, name) ->
Session.set 'openedRoom', room._id
Session.set 'editRoomTitle', false
Meteor.call 'readMessages', room._id if Meteor.userId()?
readMessage.disable()
Meteor.setTimeout ->
readMessage.refreshUnreadMark()
readMessage.enable()
readMessage.readNow()
, 2000
# KonchatNotification.removeRoomNotification(params._id)
if Meteor.Device.isDesktop()
@ -52,7 +57,11 @@ roomExit = ->
for child in mainNode.children
if child?
if child.classList.contains('room-container')
child.oldScrollTop = child.querySelector('.messages-box > .wrapper').scrollTop
wrapper = child.querySelector('.messages-box > .wrapper')
if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight
child.oldScrollTop = 10e10
else
child.oldScrollTop = wrapper.scrollTop
mainNode.removeChild child
@ -60,6 +69,7 @@ FlowRouter.route '/channel/:name',
name: 'channel'
action: (params, queryParams) ->
Session.set 'showUserInfo'
openRoom 'c', params.name
triggersExit: [roomExit]
@ -69,6 +79,7 @@ FlowRouter.route '/group/:name',
name: 'group'
action: (params, queryParams) ->
Session.set 'showUserInfo'
openRoom 'p', params.name
triggersExit: [roomExit]
@ -78,6 +89,7 @@ FlowRouter.route '/direct/:username',
name: 'direct'
action: (params, queryParams) ->
Session.set 'showUserInfo', params.username
openRoom 'd', params.username
triggersExit: [roomExit]

@ -12,20 +12,22 @@ Meteor.startup ->
unreadCount = 0
unreadAlert = false
subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1 } })
subscriptions = ChatSubscription.find({open: true}, { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1 } })
rid = undefined
if FlowRouter.getRouteName() in ['channel', 'group', 'direct']
rid = Session.get 'openedRoom'
for subscription in subscriptions.fetch()
if subscription.rid is rid and (subscription.alert or subscription.unread > 0) and document.hasFocus()
Meteor.call 'readMessages', subscription.rid
if subscription.rid is rid and (subscription.alert or subscription.unread > 0)
readMessage.readNow()
else
unreadCount += subscription.unread
if subscription.alert is true
unreadAlert = ''
readMessage.refreshUnreadMark(subscription.rid)
if unreadCount > 0
if unreadCount > 999
Session.set 'unread', '999+'
@ -43,8 +45,9 @@ Meteor.startup ->
animation: 'none'
Tracker.autorun ->
siteName = RocketChat.settings.get 'Site_Name'
unread = Session.get 'unread'
fireGlobalEvent 'unread-changed', unread
favico?.badge unread, bgColor: if typeof unread isnt 'number' then '#3d8a3a' else '#ac1b1b'
document.title = if unread == '' then 'Rocket.Chat' else '(' + unread + ') Rocket.Chat'
document.title = if unread == '' then siteName else '(' + unread + ') '+ siteName

@ -128,6 +128,48 @@ blockquote {
user-select: none;
}
.first-unread {
&.first-unread-opaque {
.body {
&::before {
background-color: #E6E6E6;
}
&::after {
color: #B3B3B3;
}
}
}
.body {
&::before {
content: "";
background-color: #FF8080;
display: block;
height: 1px;
position: absolute;
right: 0px;
left: 50px;
top: -3px;
.transition(background-color, .5s, linear);
}
&::after {
content: "unread messages";
display: block;
position: absolute;
right: 0px;
top: -7px;
text-transform: uppercase;
font-size: 8px;
line-height: 10px;
background-color: white;
padding-left: 5px;
color: #FF0000;
.transition(color, .5s, linear);
}
}
}
.text-center {
text-align: center;
}
@ -2810,7 +2852,45 @@ a.github-fork {
h3 {
font-size: 24px;
margin-bottom: 8px;
line-height: 22px;
line-height: 27px;
text-overflow: ellipsis;
width: 100%;
overflow: hidden;
white-space: nowrap;
i:after {
content: " ";
display: inline-block;
width: 8px;
height: 8px;
border-radius: 4px;
vertical-align: middle;
}
i.status-offline {
&:after {
border-color: darken(@status-offline, 5%);
background-color: @status-offline;
}
}
i.status-online {
&:after {
border-color: darken(@status-online, 5%);
background-color: @status-online;
}
}
i.status-away {
&:after {
border-color: darken(@status-away, 5%);
background-color: @status-away;
}
}
i.status-busy {
&:after {
border-color: darken(@status-busy, 5%);
background-color: @status-busy;
}
}
}
p {
line-height: 18px;

@ -25,6 +25,6 @@
@info-font-color: #AAAAAA;
@status-online: #35AC19;
@status-offline: rgba(255, 255, 255, 0.35);
@status-offline: rgba(150, 150, 150, 0.50);
@status-busy: #D30230;
@status-away: #fcb316;

@ -52,6 +52,10 @@
<th>{{_ "Stats_Total_Direct_Messages"}}</th>
<td>{{statistics.totalDirect}}</td>
</tr>
<tr>
<th>{{_ "Stats_Total_Messages"}}</th>
<td>{{statistics.totalMessages}}</td>
</tr>
<tr>
<th>{{_ "Stats_Max_Room_Users"}}</th>
<td>{{statistics.maxRoomUsers}}</td>

@ -1,17 +1,5 @@
<template name="adminUserInfo">
<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_login"}}: {{lastLogin}}</p> {{/if}}
</div>
</div>
{{> userInfo user=.}}
<nav>
<button class='button lightblue edit-user button-block'><span><i class='icon-edit'></i> {{_ "Edit"}}</span></button>
{{#if admin}}

@ -10,9 +10,9 @@ Template.adminUsers.helpers
arrowPosition: ->
return 'left' unless Session.equals('flexOpened', true)
userData: ->
return Meteor.users.findOne Session.get 'adminUsersSelected'
return Meteor.users.findOne Session.get 'adminSelectedUser'
userChannels: ->
return ChatSubscription.find({ "u._id": Session.get 'adminUsersSelected' }, { fields: { rid: 1, name: 1, t: 1 }, sort: { t: 1, name: 1 } }).fetch()
return ChatSubscription.find({ "u._id": Session.get 'adminSelectedUser' }, { fields: { rid: 1, name: 1, t: 1 }, sort: { t: 1, name: 1 } }).fetch()
isLoading: ->
return 'btn-loading' unless Template.instance().ready?.get()
hasMore: ->
@ -42,12 +42,12 @@ Template.adminUsers.onCreated ->
@autorun ->
filter = instance.filter.get()
limit = instance.limit.get()
subscription = instance.subscribe 'fullUsers', filter, limit
subscription = instance.subscribe 'fullUserData', filter, limit
instance.ready.set subscription.ready()
@autorun ->
if Session.get 'adminUsersSelected'
channelSubscription = instance.subscribe 'userChannels', Session.get 'adminUsersSelected'
if Session.get 'adminSelectedUser'
channelSubscription = instance.subscribe 'userChannels', Session.get 'adminSelectedUser'
@users = ->
filter = _.trim instance.filter?.get()
@ -83,7 +83,7 @@ Template.adminUsers.events
'click .user-info': (e) ->
e.preventDefault()
Session.set 'adminUsersSelected', $(e.currentTarget).data('id')
Session.set 'adminSelectedUser', $(e.currentTarget).data('id')
Session.set 'flexOpened', true
'click .info-tabs a': (e) ->

@ -27,8 +27,12 @@ Template.messagePopup.onCreated ->
template.textFilter = new ReactiveVar ''
template.textFilterDelay = val(template.data.textFilterDelay, 0)
template.open = new ReactiveVar false
template.hasData = new ReactiveVar false
template.value = new ReactiveVar
template.trigger = val(template.data.trigger, '@')
@ -68,9 +72,11 @@ Template.messagePopup.onCreated ->
if first?
first.className += ' selected'
template.value.set first.getAttribute('data-id')
else
template.value.set undefined
template.onInputKeydown = (event) =>
if template.open.curValue isnt true
if template.open.curValue isnt true or template.hasData.curValue isnt true
return
if event.which in [38, 40]
@ -87,7 +93,7 @@ Template.messagePopup.onCreated ->
template.setTextFilter = _.debounce (value) ->
template.textFilter.set(value)
, 200
, template.textFilterDelay
template.onInputKeyup = (event) =>
if template.open.curValue is true and event.which is 27
@ -117,6 +123,8 @@ Template.messagePopup.onCreated ->
template.verifySelection()
template.enterValue = ->
if not template.value.curValue? then return
value = template.input.value
caret = getCursorPosition(template.input)
firstPartValue = value.substr 0, caret
@ -136,8 +144,10 @@ Template.messagePopup.onCreated ->
filter = template.textFilter.get()
if filter?
result = template.data.getFilter template.data.collection, filter
# if (template.data.collection instanceof Meteor.Collection and result.count? and result.count() is 0) or result?.length is 0
# template.open.set false
if (template.data.collection instanceof Meteor.Collection and result.count? and result.count() is 0) or result?.length is 0
template.hasData.set false
else
template.hasData.set true
template.records.set result
@ -181,7 +191,7 @@ Template.messagePopup.events
Template.messagePopup.helpers
isOpen: ->
Template.instance().open.get()
Template.instance().open.get() and Template.instance().hasData.get()
data: ->
template = Template.instance()

@ -9,6 +9,7 @@ Template.messagePopupConfig.helpers
collection: onlineUsers
template: 'messagePopupUser'
getInput: self.getInput
textFilterDelay: 200
getFilter: (collection, filter) ->
exp = new RegExp(filter, 'i')
Meteor.subscribe 'onlineUsers', filter

@ -72,25 +72,9 @@ Template.room.helpers
when 'c' then return 'icon-hash'
when 'p' then return 'icon-lock'
userData: ->
roomData = Session.get('roomData' + this._id)
return {} unless roomData
if roomData.t is 'd'
username = _.without roomData.usernames, Meteor.user().username
userData = {
name: Session.get('user_' + username + '_name')
emails: Session.get('user_' + username + '_emails') || []
phone: Session.get('user_' + username + '_phone')
username: String(username)
}
if Meteor.user()?.admin is true
userData = _.extend userData, Meteor.users.findOne { username: String(username) }
return userData
flexUserInfo: ->
username = Session.get('showUserInfo')
return Meteor.users.findOne({ username: String(username) }) or { username: String(username) }
userStatus: ->
roomData = Session.get('roomData' + this._id)
@ -219,18 +203,6 @@ Template.room.helpers
return ret
flexUserInfo: ->
username = Session.get('showUserInfo')
if Meteor.user()?.admin is true
userData = _.extend { username: String(username) }, Meteor.users.findOne { username: String(username) }
else
userData = {
username: String(username)
}
return userData
seeAll: ->
if Template.instance().showUsersOffline.get()
return t('See_only_online')
@ -659,11 +631,10 @@ Template.room.onCreated ->
this.showUsersOffline = new ReactiveVar false
this.atBottom = true
# If current user is admin, subscribe to full user data
if Meteor.user()?.admin is true
Tracker.autorun ->
if Session.get('showUserInfo') and not Meteor.users.findOne Session.get 'showUserInfo'
Meteor.subscribe 'fullUsers', Session.get('showUserInfo'), 1
self = @
@autorun ->
self.subscribe 'fullUserData', Session.get('showUserInfo'), 1
Template.room.onRendered ->
FlexTab.check()
@ -691,6 +662,8 @@ Template.room.onRendered ->
wrapper.addEventListener 'touchend', ->
onscroll()
readMessage.enable()
readMessage.read()
wrapper.addEventListener 'scroll', ->
template.atBottom = false
@ -699,10 +672,14 @@ Template.room.onRendered ->
wrapper.addEventListener 'mousewheel', ->
template.atBottom = false
onscroll()
readMessage.enable()
readMessage.read()
wrapper.addEventListener 'wheel', ->
template.atBottom = false
onscroll()
readMessage.enable()
readMessage.read()
# salva a data da renderização para exibir alertas de novas mensagens
$.data(this.firstNode, 'renderedAt', new Date)

@ -172,88 +172,11 @@
{{/with}}
</div>
<div class="user-view animated{{#unless $.Session.get 'showUserInfo'}} -hidden{{/unless}}">
{{#with flexUserInfo}}
<div class="about clearfix">
<div class="thumb">
{{> avatar username=username}}
</div>
<div class="info">
<h3>{{username}}</h3>
{{#if isAdmin}}
<p>{{name}}</p>
{{#if utc}}<p><i class="icon-location"></i> {{utc}}</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_login"}}: {{lastLogin}}</p> {{/if}}
{{/if}}
</div>
</div>
<nav>
<button class='button secondary back'><span>{{_ "View_All"}} <i class='icon-angle-right'></i></span></button>
{{#if canDirectMessage}}
<button class='button pvt-msg'><span><i class='icon-chat'></i> {{_ "Conversation"}}</span></button>
{{/if}}
</nav>
{{/with}}
{{> userInfo user=flexUserInfo showAll=true}}
</div>
{{else}}
<div class="user-view">
{{#with userData}}
<div class="about clearfix">
{{#if videoActive}}
{{#if rtcLayout3}}
<div id='fullscreendiv' style="width: 100%">
<video id='videoremote' class="video-remote" src="{{remoteVideoUrl}}" style="width: 100%; align-items: center; margin-bottom: 10px; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay></video>
<video id='videoself' class="video-self" src="{{selfVideoUrl}}" style="width: 250px; position: absolute; top: 21px; right: 31px; border: 1px solid #FFF; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay muted></video>
</div>
{{/if}}
{{#if rtcLayout2}}
<div style="display: flex; flex-direction: row; align-items: center; width: 800px; height: 350px">
<video id="videoremote" class="video-remote" src="{{remoteVideoUrl}}" style="flex: 1 0; min-width: 380px; height: 285px; margin: 10px; background-color: #000;" autoplay></video>
<video id="videoself" class="video-self" src="{{selfVideoUrl}}" style="flex: 1 0; min-width: 380px; height: 285px; margin: 10px; background-color: #000;" autoplay muted></video>
</div>
{{/if}}
{{#if rtcLayout1}}
<div style="display: flex; flex-direction: column; align-items: center; width: 360px; height: 500px">
<video class="video-remote" src="{{remoteVideoUrl}}" style="flex: 1 1; width: 320px; margin: 10px; background-color: #000;" autoplay></video>
<video class="video-self" src="{{selfVideoUrl}}" style="flex: 1 1; width: 320px; margin: 10px; background-color: #000;" autoplay muted></video>
</div>
{{/if}}
{{#if noRtcLayout}}
<div>
<video class="video-remote" src="{{remoteVideoUrl}}" style="width: 100%; margin-bottom: 10px; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay></video>
<video class="video-self" src="{{selfVideoUrl}}" style="width: 100px; position: absolute; top: 21px; right: 21px; border: 1px solid #FFF; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay muted></video>
</div>
{{/if}}
{{/if}}
<div class="thumb">
{{> avatar username=username}}
</div>
<div class="info">
<h3>{{username}}</h3>
{{#if isAdmin}}
<p>{{name}}</p>
{{#if utc}}<p><i class="icon-location"></i> {{utc}}</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_login"}}: {{lastLogin}}</p> {{/if}}
{{/if}}
</div>
</div>
<nav>
{{#unless videoActive}}
<button class='button start-video'><span><i class='icon-videocam'></i> {{_ "Video_Chat"}}</span></button>
{{#if remoteMonitoring}}
<button class='button short monitor-video'><span><i class='icon-videocam'></i> {{_ "Remote"}}</span></button>
<button class='button lightblue setup-video'><span><i class='icon-videocam'></i> {{_ "Setup"}}</span></button>
{{/if}}
{{else}}
<button class='button red stop-video'><span><i class='icon-videocam'></i> {{_ "Stop_Video"}}</span></button>
{{/unless}}
</nav>
{{/with}}
{{> userInfo user=flexUserInfo video=true}}
</div>
{{/if}}
</div>

@ -0,0 +1,60 @@
Template.userInfo.helpers
isAdmin: ->
return Meteor.user()?.admin is true
utc: ->
if @utcOffset?
if @utcOffset > 0
return '+' + @utcOffset
return @utcOffset
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')
canDirectMessage: ->
return Meteor.user()?.username isnt this.username
linkedinUsername: ->
return s.strRight @services.linkedin.publicProfileUrl, '/in/'
servicesMeteor: ->
return @services?['meteor-developer']
videoActive: ->
return (Session.get('remoteVideoUrl') || Session.get('selfVideoUrl'))
rtcLayout1: ->
return (Session.get('rtcLayoutmode') == 1 ? true: false)
rtcLayout2: ->
return (Session.get('rtcLayoutmode') == 2 ? true: false)
rtcLayout3: ->
return (Session.get('rtcLayoutmode') == 3 ? true: false)
noRtcLayout: ->
return (!Session.get('rtcLayoutmode') || (Session.get('rtcLayoutmode') == 0) ? true: false)
remoteVideoUrl: ->
return Session.get('remoteVideoUrl')
selfVideoUrl: ->
return Session.get('selfVideoUrl')
userTime: ->
if @utcOffset?
return Template.instance().now.get().utcOffset(@utcOffset).format('HH:mm')
Template.userInfo.onCreated ->
@now = new ReactiveVar moment()
self = @
Meteor.setInterval ->
self.now.set moment()
, 30000

@ -0,0 +1,75 @@
<template name="userInfo">
{{#if $.Session.get 'showUserInfo'}}
{{#with user}}
<div class="about clearfix">
{{#if ../video}}
{{#if videoActive}}
{{#if rtcLayout3}}
<div id='fullscreendiv' style="width: 100%">
<video id='videoremote' class="video-remote" src="{{remoteVideoUrl}}" style="width: 100%; align-items: center; margin-bottom: 10px; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay></video>
<video id='videoself' class="video-self" src="{{selfVideoUrl}}" style="width: 250px; position: absolute; top: 21px; right: 31px; border: 1px solid #FFF; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay muted></video>
</div>
{{/if}}
{{#if rtcLayout2}}
<div style="display: flex; flex-direction: row; align-items: center; width: 800px; height: 350px">
<video id="videoremote" class="video-remote" src="{{remoteVideoUrl}}" style="flex: 1 0; min-width: 380px; height: 285px; margin: 10px; background-color: #000;" autoplay></video>
<video id="videoself" class="video-self" src="{{selfVideoUrl}}" style="flex: 1 0; min-width: 380px; height: 285px; margin: 10px; background-color: #000;" autoplay muted></video>
</div>
{{/if}}
{{#if rtcLayout1}}
<div style="display: flex; flex-direction: column; align-items: center; width: 360px; height: 500px">
<video class="video-remote" src="{{remoteVideoUrl}}" style="flex: 1 1; width: 320px; margin: 10px; background-color: #000;" autoplay></video>
<video class="video-self" src="{{selfVideoUrl}}" style="flex: 1 1; width: 320px; margin: 10px; background-color: #000;" autoplay muted></video>
</div>
{{/if}}
{{#if noRtcLayout}}
<div>
<video class="video-remote" src="{{remoteVideoUrl}}" style="width: 100%; margin-bottom: 10px; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay></video>
<video class="video-self" src="{{selfVideoUrl}}" style="width: 100px; position: absolute; top: 21px; right: 21px; border: 1px solid #FFF; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay muted></video>
</div>
{{/if}}
{{/if}}
{{/if}}
<div class="thumb">
{{> avatar username=username}}
</div>
<div class="info">
<h3 title="{{username}}"><i class="status-{{status}}"></i> {{username}}</h3>
<p>{{name}}</p>
{{#if utc}}<p><i class="icon-clock"></i>{{userTime}} (UTC {{utc}})</p>{{/if}}
{{#if isAdmin}}
{{#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-calendar"></i> {{_ "Last_login"}}: {{lastLogin}}</p> {{/if}}
{{#if services.facebook.id}} <p><i class="icon-facebook"></i><a href="{{services.facebook.link}}" target="_blank">{{services.facebook.name}}</a></p> {{/if}}
{{#if services.github.id}} <p><i class="icon-github-circled"></i><a href="https://www.github.com/{{services.github.username}}" target="_blank">{{services.github.username}}</a></p> {{/if}}
{{#if services.gitlab.id}} <p><i class="icon-gitlab"></i>{{services.gitlab.username}}</p> {{/if}}
{{#if services.google.id}} <p><i class="icon-gplus"></i><a href="https://plus.google.com/{{services.google.id}}" target="_blank">{{services.google.name}}</a></p> {{/if}}
{{#if services.linkedin.id}} <p><i class="icon-linkedin"></i><a href="{{services.linkedin.publicProfileUrl}}" target="_blank">{{linkedinUsername}}</a></p> {{/if}}
{{#if servicesMeteor.id}} <p><i class="icon-meteor"></i>{{servicesMeteor.username}}</p> {{/if}}
{{#if services.twitter.id}} <p><i class="icon-twitter"></i><a href="https://twitter.com/{{services.twitter.screenName}}" target="_blank">{{services.twitter.screenName}}</a></p> {{/if}}
{{/if}}
</div>
</div>
{{/with}}
<nav>
{{#if video}}
{{#unless videoActive}}
<button class='button start-video'><span><i class='icon-videocam'></i> {{_ "Video_Chat"}}</span></button>
{{#if remoteMonitoring}}
<button class='button short monitor-video'><span><i class='icon-videocam'></i> {{_ "Remote"}}</span></button>
<button class='button lightblue setup-video'><span><i class='icon-videocam'></i> {{_ "Setup"}}</span></button>
{{/if}}
{{else}}
<button class='button red stop-video'><span><i class='icon-videocam'></i> {{_ "Stop_Video"}}</span></button>
{{/unless}}
{{/if}}
{{#if showAll}}
<button class='button secondary back'><span>{{_ "View_All"}} <i class='icon-angle-right'></i></span></button>
{{#if canDirectMessage}}
<button class='button pvt-msg'><span><i class='icon-chat'></i> {{_ "Conversation"}}</span></button>
{{/if}}
{{/if}}
</nav>
{{/if}}
</template>

@ -81,6 +81,9 @@ Template.body.onRendered ->
Template.main.helpers
siteName: ->
return RocketChat.settings.get 'Site_Name'
logged: ->
if Meteor.userId()?
$('html').addClass("noscroll").removeClass("scroll")

@ -222,6 +222,7 @@
"Showing_results" : "<p>Showing <b>%s</b> results</p>",
"Silence" : "Silence",
"since_creation" : "since %s",
"Site_Name" : "Site Name:",
"SMTP_Host" : "SMTP Host",
"SMTP_Password" : "SMTP Password",
"SMTP_Port" : "SMTP Port",
@ -245,7 +246,8 @@
"Stats_OS_Type": "OS Type",
"Stats_OS_Uptime": "OS Uptime",
"Stats_Total_Channels": "Total Channels",
"Stats_Total_Direct_Messages": "Total Direct Messages",
"Stats_Total_Direct_Messages": "Total Direct Messages Rooms",
"Stats_Total_Messages": "Total Messages",
"Stats_Total_Private_Groups": "Total Private Groups",
"Stats_Total_Rooms": "Total Rooms",
"Stats_Total_Users": "Total Users",

@ -2,7 +2,7 @@
// the entire section is optional.
App.info({
id: 'com.konecty.rocket.chat',
version: '0.1.3',
version: '0.1.4',
name: 'Rocket.Chat',
description: 'Rocket.Chat',
author: 'Rocket.Chat Development Group',

@ -19,6 +19,9 @@ RocketChat.getStatistics = ->
statistics.totalPrivateGroups = ChatRoom.find({ t: 'p' }).count()
statistics.totalDirect = ChatRoom.find({ t: 'd' }).count()
# Message statistics
statistics.totalMessages = ChatMessage.find().count()
m = ->
emit 1,
sum: this.usernames.length or 0

@ -27,6 +27,9 @@ Meteor.startup ->
RocketChat.settings.add 'Accounts_Twitter_secret', '', { type: 'string', group: 'Accounts' }
RocketChat.settings.add 'Accounts_ManuallyApproveNewUsers', false, { type: 'boolean', group: 'Accounts' }
RocketChat.settings.addGroup 'General'
RocketChat.settings.add 'Site_Name', 'Rocket.Chat', { type: 'string', group: 'General', public: true }
RocketChat.settings.addGroup 'API'
RocketChat.settings.add 'API_Analytics', '', { type: 'string', group: 'API', public: true }
RocketChat.settings.add 'API_Embed', true, { type: 'boolean', group: 'API', public: true }

@ -0,0 +1,44 @@
Meteor.publish 'fullUserData', (filter, limit) ->
unless @userId
return @ready()
user = Meteor.users.findOne @userId
fields =
name: 1
username: 1
status: 1
utcOffset: 1
if user.admin is true
fields = _.extend fields,
emails: 1
phone: 1
statusConnection: 1
admin: 1
lastLogin: 1
active: 1
services: 1
else
limit = 1
filter = s.trim filter
if not filter and limit is 1
return @ready()
if filter
if limit is 1
query = { username: filter }
else
filterReg = new RegExp filter, "i"
query = { $or: [ { username: filterReg }, { name: filterReg }, { "emails.address": filterReg } ] }
else
query = {}
console.log '[publish] fullUserData'.green, filter, limit
Meteor.users.find query,
fields: fields
limit: limit
sort: { username: 1 }

@ -1,37 +0,0 @@
Meteor.publish 'fullUsers', (filter, limit) ->
unless this.userId
return this.ready()
user = Meteor.users.findOne this.userId
if user.admin isnt true
return this.ready()
filter = _.trim filter
if filter
if limit is 1
query = { username: filter }
else
filterReg = new RegExp filter, "i"
query = { $or: [ { username: filterReg }, { name: filterReg }, { "emails.address": filterReg } ] }
else
query = {}
console.log '[publish] fullUsers'.green, filter, limit
Meteor.users.find query,
fields:
name: 1
username: 1
emails: 1
phone: 1
status: 1
statusDefault: 1
statusConnection: 1
avatarOrigin: 1
admin: 1
utcOffset: 1
language: 1
lastLogin: 1
active: 1
limit: limit
sort: { username: 1 }

@ -14,4 +14,3 @@ Meteor.startup ->
try ChatMessage._ensureIndex { 'ets': 1 }, { sparse: 1 } catch e then console.log e
try ChatMessage._ensureIndex { 'rid': 1, 't': 1, 'u._id': 1 } catch e then console.log e
try ChatMessage._ensureIndex { 'expireAt': 1 }, { expireAfterSeconds: 0 } catch e then console.log e
try ChatMessage._ensureIndex { '_hidden': 1 }, { sparse: 1 } catch e then console.log e

@ -0,0 +1,6 @@
Meteor.startup ->
Migrations.add
version: 16
up: ->
rawMessage = ChatMessage.rawCollection()
Meteor.wrapAsync(rawMessage.dropIndex, rawMessage)({ _hidden: 1 })

@ -0,0 +1,6 @@
Meteor.startup ->
Migrations.add
version: 17
up: ->
rawMessage = ChatMessage.rawCollection()
Meteor.wrapAsync(rawMessage.dropIndex, rawMessage)({ _hidden: 1 })
Loading…
Cancel
Save