Merge pull request #185 from RocketChat/master

Keeping sync
pull/188/head
Gabriel Engel 11 years ago
commit dd38387901
  1. 17
      .meteor/packages
  2. 12
      .meteor/versions
  3. 6
      client/methods/sendMessage.coffee
  4. 42
      client/stylesheets/base.less
  5. 225
      client/stylesheets/rtl.less
  6. 22
      client/views/app/chatMessageDashboard.coffee
  7. 8
      client/views/app/chatMessageDashboard.html
  8. 13
      client/views/app/chatWindowDashboard.html
  9. 2
      client/views/app/layout.coffee
  10. 2
      client/views/app/privateHistory.html
  11. 2
      client/views/app/sideNav/createChannelFlex.html
  12. 4
      client/views/app/sideNav/privateGroupsFlex.html
  13. 2
      client/views/login/form.html
  14. 2
      client/views/username/prompt.html
  15. 2
      packages/rocketchat-autolinker/autolinker.coffee
  16. 2
      packages/rocketchat-emojione/emojione.coffee
  17. 16
      packages/rocketchat-file/package.js
  18. 8
      packages/rocketchat-highlight/highlight.coffee
  19. 1
      packages/rocketchat-hubot/.npm/package/.gitignore
  20. 7
      packages/rocketchat-hubot/.npm/package/README
  21. 744
      packages/rocketchat-hubot/.npm/package/npm-shrinkwrap.json
  22. 200
      packages/rocketchat-hubot/hubot.coffee
  23. 32
      packages/rocketchat-hubot/package.js
  24. 22
      packages/rocketchat-markdown/markdown.coffee
  25. 2
      packages/rocketchat-me/me.coffee
  26. 2
      packages/rocketchat-mentions/client.coffee
  27. 2
      packages/rocketchat-mentions/package.js
  28. 21
      packages/rocketchat-tmpembed/package.js
  29. 29
      packages/rocketchat-tmpembed/tmpembed.coffee
  30. BIN
      public/images/logo/512x512.jpg
  31. 14
      server/methods/sendMessage.coffee

@ -17,7 +17,9 @@ markdown
meteor-platform
reactive-var
service-configuration
chrismbeckett:toastr
dispatch:kernel
francocatena:status
iframely:oembed
iron:router
@ -31,29 +33,26 @@ meteorhacks:kadira
mizzao:autocomplete
mizzao:timesync
momentjs:moment
monbro:mongodb-mapreduce-aggregation
mrt:reactive-store
nooitaf:colors
pauli:accounts-linkedin
percolate:migrations
percolatestudio:synced-cron
pierreeric:rxfavico
raix:handlebar-helpers
rocketchat:autolinker
rocketchat:emojione
rocketchat:file
rocketchat:highlight
#rocketchat:hubot
rocketchat:lib
rocketchat:markdown
rocketchat:me
rocketchat:mentions
rocketchat:highlight
rocketchat:autolinker
rocketchat:markdown
rocketchat:emojione
simple:highlight.js
rocketchat:tmpembed
tap:i18n
tmeasday:crypto-md5
tmeasday:errors
todda00:friendly-slugs
underscorestring:underscore.string
yasaricli:slugify
emojione:emojione

@ -20,9 +20,10 @@ coffeescript@1.0.6
dandv:caret-position@2.1.1
ddp@1.1.0
deps@1.0.7
dispatch:kernel@0.0.6
dispatch:request-animation-frame@0.0.1
ejson@1.0.6
email@1.0.6
emojione:emojione@1.4.1
facebook@1.2.0
fastclick@1.0.3
francocatena:status@1.2.3
@ -62,15 +63,15 @@ matb33:collection-hooks@0.7.13
meteor@1.1.6
meteor-developer@1.1.3
meteor-platform@1.2.2
meteorhacks:kadira@2.21.0
meteorhacks:kadira@2.22.0
meteorhacks:meteorx@1.3.1
meteorspark:util@0.2.0
minifiers@1.1.5
minimongo@1.0.8
mizzao:autocomplete@0.5.1
mizzao:timesync@0.3.1
mobile-status-bar@1.0.3
momentjs:moment@2.10.3
monbro:mongodb-mapreduce-aggregation@1.0.1
mongo@1.1.0
mongo-livedata@1.0.8
mrt:reactive-store@0.0.1
@ -85,6 +86,8 @@ pauli:linkedin@1.1.2
percolate:migrations@0.7.5
percolatestudio:synced-cron@1.1.0
pierreeric:rxfavico@0.3.5_1
qnub:emojione@0.0.3
raix:eventemitter@0.1.2
raix:handlebar-helpers@0.2.4
random@1.0.3
reactive-dict@1.1.0
@ -99,6 +102,7 @@ rocketchat:lib@0.0.1
rocketchat:markdown@0.0.1
rocketchat:me@0.0.1
rocketchat:mentions@0.0.1
rocketchat:tmpembed@0.0.1
routepolicy@1.0.5
service-configuration@1.0.4
session@1.1.0
@ -107,7 +111,7 @@ simple:highlight.js@1.0.9
spacebars@1.0.6
spacebars-compiler@1.0.6
srp@1.0.3
tap:i18n@1.4.1
tap:i18n@1.5.0
templating@1.1.1
tmeasday:crypto-base@3.1.2
tmeasday:crypto-md5@3.1.2

@ -11,10 +11,10 @@ Meteor.methods
username: Meteor.user().username
message.html = message.msg
if _.trim(message.html) isnt ''
message.html = _.escapeHTML message.html
message = RocketChat.callbacks.run 'beforeSaveMessage', message
message.html = message.html.replace /\n/g, '<br/>'
console.log message
message.html = message.html.replace /\n/gm, '<br/>'
ChatMessage.upsert
rid: message.rid

@ -41,7 +41,7 @@ a {
code {
background: #f8f8f8;
border-radius: 6px;
border-radius: 4px;
border: 1px solid #ccc;
color: #333;
display: block;
@ -49,6 +49,24 @@ code {
overflow-x: auto;
padding: 0.5em;
word-wrap: break-word;
&.inline {
display: inline-block;
padding: 0 10px;
margin: 0;
vertical-align: bottom;
}
}
q {
padding-left: 10px;
&:before {
content: ' ';
background-color: #ccc;
height: 22px;
width: 3px;
position: absolute;
left: 50px;
}
}
.text-center {
@ -1622,7 +1640,7 @@ a.github-fork {
}
.footer {
position: absolute;
padding: 14px 20px 0px 20px;
padding: 8px 20px 0px 20px;
background: #fff;
border-top: 1px solid @tertiary-background-color;
z-index: 100;
@ -1683,11 +1701,31 @@ a.github-fork {
}
}
> .users-typing {
float: left;
height: 20px;
font-size: 12px;
color: #888;
padding: 3px 0px 0px 5px;
}
> .formatting-tips {
float: right;
height: 20px;
font-size: 11px;
color: #888;
padding: 4px 0px 0px 5px;
display: inline-block;
white-space: nowrap;
q {
padding: 0 0 0 3px;
border-left: 3px solid #ccc;
&:before {
content: none !important;
}
}
code {
color: #888;
}
}
}
.add-user-search {
height: 100%;

@ -0,0 +1,225 @@
.rtl
{
direction: rtl;
// Mix-ins
.right(@right) {
right: @right;
left: auto;
}
.left (@left) {
left: @left;
right: auto;
}
.margin-right(@margin-right) {
margin-right: @margin-right;
margin-left: auto;
}
.margin-left(@margin-left) {
margin-left: @margin-left;
margin-right: auto;
}
.padding-right(@padding-right) {
padding-right: @padding-right;
padding-left: 0px;
}
.padding-left(@padding-left) {
padding-left: @padding-left;
padding-right: 0px;
}
.side-nav {
.right(0px);
.header {
.right(0px);
.account-box {
.info {
padding: 10px 18px 10px 0px;
.thumb {
float: right;
}
.thumb:after {
.right(-14px);
}
.data {
float: right;
padding: 0 10px 0 25px;
.wrp {
text-align: right;
}
}
}
.options {
.right(0px);
.status {
.padding-right(38px);
}
span.soon {
.left(-30px);
}
.status:after {
.right(18px);
}
}
.options._hidden {
transform: translateX(100%);
}
}
}
> .arrow {
.left(8px);
}
.arrow {
transform: rotateY(180deg);
}
.flex-nav {
.right(0px);
}
.flex-nav.hidden {
transform: translateX(100%);
}
.footer {
.right(0px);
}
.rooms-list {
> .wrapper {
direction: rtl;
.padding-right(8px);
h3.add-room
{
i {
.left(6px);
}
}
h3 {
.padding-right(10px);
}
ul a {
padding: 6px 6px 7px 25px;
}
}
}
.more {
padding: 4px 10px 4px 0px;
}
.empty {
.padding-right(10px);
}
ul .opt {
.left(0px);
}
.flex-nav {
> section {
.right(0px);
}
header {
.right(0px);
.padding-right(15px);
> div {
text-align: right;
}
}
.content {
> .wrapper {
direction: rtl;
}
}
.input-submit {
margin: 35px -4px 0 0px;
}
.button:before {
.right(0px);
}
footer {
.right(0px);
text-align: right;
> div {
text-align: right;
}
}
}
}
.side-nav:before {
.right(8px);
}
.main-content {
.margin-right(260px);
}
.messages-box {
.message {
.padding-right(50px);
}
.thumb {
.right(0px);
}
.message.with-thumb .time {
.right(4px);
}
.time-single {
.right(-15px);
}
}
.messages-container {
.message-form {
textarea {
padding-left: 38px;
padding-right: 8px;
}
> .formatting-tips {
float: left;
}
.icon-paper-plane {
.left(10px);
transform: rotateY(180deg);
}
}
}
q {
.padding-right(10px);
}
q:before {
.right(50px);
}
}

@ -14,6 +14,14 @@ Template.chatMessageDashboard.helpers
isEditing: ->
return this._id is Session.get('editingMessageId')
renderMessage: ->
this.html = this.msg
if _.trim(this.html) isnt ''
this.html = _.escapeHTML this.html
message = RocketChat.callbacks.run 'renderMessage', this
this.html = message.html.replace /\n/gm, '<br/>'
return this.html
message: ->
switch this.t
when 'r' then t('chatMessageDashboard.Room_name_changed', { room_name: this.msg, user_by: Session.get('user_' + this.u._id + '_name') }) + '.'
@ -27,20 +35,6 @@ Template.chatMessageDashboard.helpers
time: ->
return moment(this.ts).format('HH:mm')
newMessage: ->
# @TODO pode melhorar, acho que colocando as salas abertas na sessão
# if $('#chat-window-' + this.rid + '.opened').length == 0
# return 'new'
preMD: Template 'preMD', ->
self = this
text = ""
if self.templateContentBlock
text = Blaze._toText(self.templateContentBlock, HTML.TEXTMODE.STRING)
text = text.replace(/#/g, '\\#')
return text
getPupupConfig: ->
template = Template.instance()
return {

@ -4,7 +4,7 @@
<span>{{messageDate data.ts}}</span>
</li>
{{/if}}
<li class="message {{#unless single}}with-thumb{{/unless}} {{own}} {{data.type}}" data-scroll-to-bottom="{{scroll}}">
<li id="{{data._id}}" class="message {{#unless single}}with-thumb{{/unless}} {{own}} {{data.type}}" data-scroll-to-bottom="{{scroll}}">
{{#with data}}
{{#if isSystemMessage}}
<p class="system">{{{message}}}</p>
@ -25,7 +25,7 @@
{{#if isEditing}}
<div class="input-message-editing-container">
{{> messagePopupConfig getPupupConfig}}
<textarea class="input-message-editing">{{msg}}</textarea>
<textarea class="input-message-editing" dir="auto">{{msg}}</textarea>
</div>
{{else}}
{{#if ../single}}
@ -41,8 +41,8 @@
{{/if}}
</span>
{{/if}}
<div>
{{{html}}}
<div dir="auto">
{{{renderMessage}}}
</div>
{{/if}}
{{/if}}

@ -13,7 +13,7 @@
<i class="{{roomTypeIcon}}"></i>
<span class="room-title {{editingTitle}}">{{roomName}}</span>
{{#if canEditName}}
<input type="text" id="room-title-field" class="{{showEditingTitle}}" value="{{roomNameEdit}}">
<input type="text" id="room-title-field" class="{{showEditingTitle}}" value="{{roomNameEdit}}" dir="auto">
<a href="#edit" class="edit-room-title"><i class="icon-pencil"></i></a>
{{/if}}
</h2>
@ -57,9 +57,8 @@
<footer class="footer">
<form class="message-form" method="post" action="/">
<div>
<!--input type="text" class="input-message" value="" /-->
{{> messagePopupConfig getPupupConfig}}
<textarea name="msg" class="input-message"></textarea>
<textarea dir="auto" name="msg" class="input-message"></textarea>
<i class="icon-paper-plane" title="{{_ "chatWindowDashboard.Send_Message"}}"></i>
</div>
<div class="users-typing">
@ -80,6 +79,14 @@
{{/if}}
{{/with}}
</div>
<div class="formatting-tips" aria-hidden="true" dir="auto">
<b>*bold*</b>
<i>_italics_</i>
~<strike>strike</strike>~
<code class="inline">`inline code`</code>
<code class="inline">```⏎multi⏎line⏎```</code>
<q>&gt;quote</q>
</div>
</form>
</footer>
</section>

@ -4,3 +4,5 @@ Template.appLayout.helpers
Template.appLayout.rendered = ->
$('html').addClass("noscroll").removeClass "scroll"
# RTL Support - Need config option on the UI
# $('html').addClass("rtl")

@ -10,7 +10,7 @@
<div class="content">
<form class="search-form" role="form">
<div class="input-line search">
<input type="text" id="history-filter" placeholder="{{_ "general.Search"}}">
<input type="text" id="history-filter" placeholder="{{_ "general.Search"}}" dir="auto">
<i class="icon-search"></i>
</div>
</form>

@ -9,7 +9,7 @@
<h4>{{_ "chatRooms.Create_new_channel" }}</h4>
<div class="input-line">
<label for="channel-name">{{_ "chatRooms.Name"}}</label>
<input type="text" id="channel-name" class="required">
<input type="text" id="channel-name" class="required" dir="auto">
</div>
<div class="input-line">
<label for="channel-members">Add Members</label>

@ -9,7 +9,7 @@
<h4>Create a new private group</h4>
<div class="input-line">
<label for="pvt-group-name">{{_ "chatRooms.Name"}}</label>
<input type="text" id="pvt-group-name" class="required">
<input type="text" id="pvt-group-name" class="required" dir="auto">
</div>
<div class="input-line">
<label for="pvt-group-members">{{_ "chatRooms.Members" }}</label>
@ -34,4 +34,4 @@
</div>
</div>
</div>
</template>
</template>

@ -10,7 +10,7 @@
{{/if}}
<div class="fields">
<div class='input-text active {{showName}}'>
<input type="text" name='name' placeholder='{{_ "general.Name"}}' />
<input type="text" name='name' placeholder='{{_ "general.Name"}}' dir="auto"/>
</div>
<div class='input-text active {{showEmailOrUsername}}'>
<input type="text" name='emailOrUsername' placeholder='{{_ "login.Email_or_username"}}' />

@ -23,7 +23,7 @@
<div class='input-text active'>
{{#if username.ready}}
<span>
<input type="text" name='username' value="{{username.username}}" placeholder='{{_ "usernameRegistration.Username"}}' />
<input type="text" name='username' value="{{username.username}}" placeholder='{{_ "usernameRegistration.Username"}}' dir="auto"/>
</span>
<i></i>
{{else}}

@ -10,4 +10,4 @@ class AutoLinker
return message
RocketChat.callbacks.add 'beforeSaveMessage', AutoLinker
RocketChat.callbacks.add 'renderMessage', AutoLinker

@ -10,4 +10,4 @@ class Emojione
return message
RocketChat.callbacks.add 'beforeSaveMessage', Emojione, RocketChat.callbacks.priority.LOW
RocketChat.callbacks.add 'renderMessage', Emojione, RocketChat.callbacks.priority.LOW

@ -5,22 +5,22 @@ Package.describe({
git: ''
});
Npm.depends({
'mkdirp': '0.3.5',
'gridfs-stream': '0.5.3',
'gm' :'1.18.1'
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use('coffeescript');
api.use(['coffeescript']);
api.addFiles('file.server.coffee', 'server');
api.addFiles('file.server.coffee', ['server']);
api.export(['RocketChatFile'], ['server']);
});
Npm.depends({
'mkdirp': '0.3.5',
'gridfs-stream': '0.5.3',
'gm': '1.18.1'
});
Package.onTest(function(api) {
});

@ -4,7 +4,7 @@
###
class Highlight
# If message starts with ```, replace it for text formatting
constructor: (message) ->
@ -18,7 +18,7 @@ class Highlight
if codeMatch?
# Process highlight if this part is code
lang = codeMatch[1]
code = codeMatch[2]
code = _.unescapeHTML codeMatch[2]
if lang not in hljs.listLanguages()
result = hljs.highlightAuto code
else
@ -26,8 +26,6 @@ class Highlight
msgParts[index] = "<pre><code class='hljs " + result.language + "'>" + result.value + "</code></pre>"
else
# Escape html and fix line breaks for non code blocks
part = _.escapeHTML part
part = part.replace /\n/g, '<br/>'
msgParts[index] = part
# Re-mount message
@ -35,4 +33,4 @@ class Highlight
return message
RocketChat.callbacks.add 'beforeSaveMessage', Highlight, RocketChat.callbacks.priority.HIGH
RocketChat.callbacks.add 'renderMessage', Highlight, RocketChat.callbacks.priority.HIGH

@ -0,0 +1,7 @@
This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.
You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.

@ -0,0 +1,744 @@
{
"dependencies": {
"codex-blackboard-hubot-scripts": {
"version": "https://github.com/cscott/codex-blackboard-hubot-scripts/tarball/f57c178a2faee9b36d07a7905c29093b9824e0b0",
"dependencies": {
"hubot-calculator": {
"version": "0.4.0",
"dependencies": {
"coffee-script": {
"version": "1.6.3"
},
"mathjs": {
"version": "1.7.0",
"dependencies": {
"decimal.js": {
"version": "4.0.2"
}
}
}
}
},
"hubot-google-hangouts": {
"version": "0.7.1",
"dependencies": {
"coffee-script": {
"version": "1.6.3"
},
"googleapis": {
"version": "0.4.7",
"dependencies": {
"request": {
"version": "2.25.0",
"dependencies": {
"qs": {
"version": "0.6.6"
},
"json-stringify-safe": {
"version": "5.0.1"
},
"forever-agent": {
"version": "0.5.2"
},
"tunnel-agent": {
"version": "0.3.0"
},
"http-signature": {
"version": "0.10.1",
"dependencies": {
"assert-plus": {
"version": "0.1.5"
},
"asn1": {
"version": "0.1.11"
},
"ctype": {
"version": "0.5.3"
}
}
},
"hawk": {
"version": "1.0.0",
"dependencies": {
"hoek": {
"version": "0.9.1"
},
"boom": {
"version": "0.4.2"
},
"cryptiles": {
"version": "0.2.2"
},
"sntp": {
"version": "0.2.4"
}
}
},
"aws-sign": {
"version": "0.3.0"
},
"oauth-sign": {
"version": "0.3.0"
},
"cookie-jar": {
"version": "0.3.0"
},
"node-uuid": {
"version": "1.4.3"
},
"mime": {
"version": "1.2.11"
},
"form-data": {
"version": "0.1.4",
"dependencies": {
"combined-stream": {
"version": "0.0.7",
"dependencies": {
"delayed-stream": {
"version": "0.0.5"
}
}
},
"async": {
"version": "0.9.2"
}
}
}
}
},
"async": {
"version": "0.2.6"
},
"gapitoken": {
"version": "0.1.0",
"dependencies": {
"jws": {
"version": "0.0.2",
"dependencies": {
"tap": {
"version": "0.3.3",
"dependencies": {
"inherits": {
"version": "1.0.0"
},
"yamlish": {
"version": "0.0.5"
},
"slide": {
"version": "1.1.6"
},
"runforcover": {
"version": "0.0.2",
"dependencies": {
"bunker": {
"version": "0.1.2",
"dependencies": {
"burrito": {
"version": "0.2.12",
"dependencies": {
"traverse": {
"version": "0.5.2"
},
"uglify-js": {
"version": "1.1.1"
}
}
}
}
}
}
},
"nopt": {
"version": "2.2.1",
"dependencies": {
"abbrev": {
"version": "1.0.7"
}
}
},
"mkdirp": {
"version": "0.3.5"
},
"difflet": {
"version": "0.2.6",
"dependencies": {
"traverse": {
"version": "0.6.6"
},
"charm": {
"version": "0.1.2"
},
"deep-is": {
"version": "0.1.3"
}
}
},
"deep-equal": {
"version": "0.0.0"
},
"buffer-equal": {
"version": "0.0.1"
}
}
},
"base64url": {
"version": "0.0.3"
}
}
}
}
}
}
}
}
},
"hubot-google-images": {
"version": "0.1.5"
},
"hubot-google-translate": {
"version": "0.1.0"
},
"hubot-help": {
"version": "0.1.1"
},
"hubot-scripts": {
"version": "2.16.1",
"dependencies": {
"redis": {
"version": "0.8.4"
}
}
},
"hubot-youtube": {
"version": "0.1.2"
}
}
},
"coffee-script": {
"version": "1.9.3"
},
"hubot": {
"version": "2.13.1",
"dependencies": {
"chalk": {
"version": "1.0.0",
"dependencies": {
"ansi-styles": {
"version": "2.0.1"
},
"escape-string-regexp": {
"version": "1.0.3"
},
"has-ansi": {
"version": "1.0.3",
"dependencies": {
"ansi-regex": {
"version": "1.1.1"
},
"get-stdin": {
"version": "4.0.1"
}
}
},
"strip-ansi": {
"version": "2.0.1",
"dependencies": {
"ansi-regex": {
"version": "1.1.1"
}
}
},
"supports-color": {
"version": "1.3.1"
}
}
},
"cline": {
"version": "0.8.2"
},
"coffee-script": {
"version": "1.6.3"
},
"connect-multiparty": {
"version": "1.2.5",
"dependencies": {
"multiparty": {
"version": "3.3.2",
"dependencies": {
"readable-stream": {
"version": "1.1.13",
"dependencies": {
"core-util-is": {
"version": "1.0.1"
},
"isarray": {
"version": "0.0.1"
},
"string_decoder": {
"version": "0.10.31"
},
"inherits": {
"version": "2.0.1"
}
}
},
"stream-counter": {
"version": "0.2.0"
}
}
},
"on-finished": {
"version": "2.1.1",
"dependencies": {
"ee-first": {
"version": "1.1.0"
}
}
},
"qs": {
"version": "2.2.5"
},
"type-is": {
"version": "1.5.7",
"dependencies": {
"media-typer": {
"version": "0.3.0"
},
"mime-types": {
"version": "2.0.14",
"dependencies": {
"mime-db": {
"version": "1.12.0"
}
}
}
}
}
}
},
"express": {
"version": "3.18.1",
"dependencies": {
"basic-auth": {
"version": "1.0.0"
},
"connect": {
"version": "2.27.1",
"dependencies": {
"basic-auth-connect": {
"version": "1.0.0"
},
"body-parser": {
"version": "1.9.3",
"dependencies": {
"iconv-lite": {
"version": "0.4.5"
},
"on-finished": {
"version": "2.1.1",
"dependencies": {
"ee-first": {
"version": "1.1.0"
}
}
},
"qs": {
"version": "2.3.3"
},
"raw-body": {
"version": "1.3.1"
}
}
},
"bytes": {
"version": "1.0.0"
},
"cookie-parser": {
"version": "1.3.5",
"dependencies": {
"cookie": {
"version": "0.1.3"
},
"cookie-signature": {
"version": "1.0.6"
}
}
},
"compression": {
"version": "1.2.2",
"dependencies": {
"accepts": {
"version": "1.1.4",
"dependencies": {
"mime-types": {
"version": "2.0.14",
"dependencies": {
"mime-db": {
"version": "1.12.0"
}
}
},
"negotiator": {
"version": "0.4.9"
}
}
},
"compressible": {
"version": "2.0.3",
"dependencies": {
"mime-db": {
"version": "1.13.0"
}
}
}
}
},
"connect-timeout": {
"version": "1.4.0",
"dependencies": {
"ms": {
"version": "0.6.2"
}
}
},
"csurf": {
"version": "1.6.6",
"dependencies": {
"csrf": {
"version": "2.0.7",
"dependencies": {
"base64-url": {
"version": "1.2.1"
},
"rndm": {
"version": "1.1.0"
},
"scmp": {
"version": "1.0.0"
},
"uid-safe": {
"version": "1.1.0",
"dependencies": {
"native-or-bluebird": {
"version": "1.1.2"
}
}
}
}
}
}
},
"errorhandler": {
"version": "1.2.4",
"dependencies": {
"accepts": {
"version": "1.1.4",
"dependencies": {
"mime-types": {
"version": "2.0.14",
"dependencies": {
"mime-db": {
"version": "1.12.0"
}
}
},
"negotiator": {
"version": "0.4.9"
}
}
}
}
},
"express-session": {
"version": "1.9.3",
"dependencies": {
"crc": {
"version": "3.2.1"
},
"uid-safe": {
"version": "1.0.1",
"dependencies": {
"mz": {
"version": "1.3.0",
"dependencies": {
"native-or-bluebird": {
"version": "1.2.0"
},
"thenify": {
"version": "3.1.0"
},
"thenify-all": {
"version": "1.6.0"
}
}
},
"base64-url": {
"version": "1.2.1"
}
}
}
}
},
"finalhandler": {
"version": "0.3.2",
"dependencies": {
"on-finished": {
"version": "2.1.1",
"dependencies": {
"ee-first": {
"version": "1.1.0"
}
}
}
}
},
"http-errors": {
"version": "1.2.8",
"dependencies": {
"inherits": {
"version": "2.0.1"
},
"statuses": {
"version": "1.2.1"
}
}
},
"method-override": {
"version": "2.3.3",
"dependencies": {
"debug": {
"version": "2.2.0",
"dependencies": {
"ms": {
"version": "0.7.1"
}
}
},
"methods": {
"version": "1.1.1"
}
}
},
"morgan": {
"version": "1.4.1",
"dependencies": {
"on-finished": {
"version": "2.1.1",
"dependencies": {
"ee-first": {
"version": "1.1.0"
}
}
}
}
},
"multiparty": {
"version": "3.3.2",
"dependencies": {
"readable-stream": {
"version": "1.1.13",
"dependencies": {
"core-util-is": {
"version": "1.0.1"
},
"isarray": {
"version": "0.0.1"
},
"string_decoder": {
"version": "0.10.31"
},
"inherits": {
"version": "2.0.1"
}
}
},
"stream-counter": {
"version": "0.2.0"
}
}
},
"on-headers": {
"version": "1.0.0"
},
"qs": {
"version": "2.3.0"
},
"response-time": {
"version": "2.2.0"
},
"serve-favicon": {
"version": "2.1.7",
"dependencies": {
"ms": {
"version": "0.6.2"
}
}
},
"serve-index": {
"version": "1.5.3",
"dependencies": {
"accepts": {
"version": "1.1.4",
"dependencies": {
"negotiator": {
"version": "0.4.9"
}
}
},
"batch": {
"version": "0.5.1"
},
"mime-types": {
"version": "2.0.14",
"dependencies": {
"mime-db": {
"version": "1.12.0"
}
}
}
}
},
"serve-static": {
"version": "1.7.2"
},
"type-is": {
"version": "1.5.7",
"dependencies": {
"mime-types": {
"version": "2.0.14",
"dependencies": {
"mime-db": {
"version": "1.12.0"
}
}
}
}
},
"vhost": {
"version": "3.0.0"
},
"pause": {
"version": "0.0.1"
}
}
},
"content-disposition": {
"version": "0.5.0"
},
"commander": {
"version": "1.3.2",
"dependencies": {
"keypress": {
"version": "0.1.0"
}
}
},
"cookie-signature": {
"version": "1.0.5"
},
"debug": {
"version": "2.1.3",
"dependencies": {
"ms": {
"version": "0.7.0"
}
}
},
"depd": {
"version": "1.0.1"
},
"escape-html": {
"version": "1.0.1"
},
"etag": {
"version": "1.5.1",
"dependencies": {
"crc": {
"version": "3.2.1"
}
}
},
"fresh": {
"version": "0.2.4"
},
"media-typer": {
"version": "0.3.0"
},
"methods": {
"version": "1.1.0"
},
"mkdirp": {
"version": "0.5.0",
"dependencies": {
"minimist": {
"version": "0.0.8"
}
}
},
"parseurl": {
"version": "1.3.0"
},
"proxy-addr": {
"version": "1.0.8",
"dependencies": {
"forwarded": {
"version": "0.1.0"
},
"ipaddr.js": {
"version": "1.0.1"
}
}
},
"range-parser": {
"version": "1.0.2"
},
"send": {
"version": "0.10.1",
"dependencies": {
"destroy": {
"version": "1.0.3"
},
"mime": {
"version": "1.2.11"
},
"ms": {
"version": "0.6.2"
},
"on-finished": {
"version": "2.1.1",
"dependencies": {
"ee-first": {
"version": "1.1.0"
}
}
}
}
},
"utils-merge": {
"version": "1.0.0"
},
"vary": {
"version": "1.0.0"
},
"cookie": {
"version": "0.1.2"
},
"merge-descriptors": {
"version": "0.0.2"
}
}
},
"log": {
"version": "1.4.0"
},
"optparse": {
"version": "1.0.4"
},
"scoped-http-client": {
"version": "0.11.0"
}
}
}
}
}

@ -0,0 +1,200 @@
CoffeeScript = Npm.require('coffee-script')
CoffeeScript.register()
HubotScripts = Npm.require('codex-blackboard-hubot-scripts');
Hubot = Npm.require('hubot')
# Start a hubot, connected to our chat room.
'use strict'
# Log messages?
DEBUG = true
# Monkey-patch Hubot to support private messages
Hubot.Response::priv = (strings...) ->
@robot.adapter.priv @envelope, strings...
# More monkey-patching
Hubot.Robot::loadAdapter = -> # disable
# grrrr, Meteor.bindEnvironment doesn't preserve `this` apparently
bind = (f) ->
g = Meteor.bindEnvironment (self, args...) -> f.apply(self, args)
(args...) -> g @, args...
class Robot extends Hubot.Robot
constructor: (args...) ->
super args...
@hear = bind @hear
@respond = bind @respond
@enter = bind @enter
@leave = bind @leave
@topic = bind @topic
@error = bind @error
@catchAll = bind @catchAll
loadAdapter: -> false
hear: (regex, callback) -> super regex, Meteor.bindEnvironment callback
respond: (regex, callback) -> super regex, Meteor.bindEnvironment callback
enter: (callback) -> super Meteor.bindEnvironment(callback)
leave: (callback) -> super Meteor.bindEnvironment(callback)
topic: (callback) -> super Meteor.bindEnvironment(callback)
error: (callback) -> super Meteor.bindEnvironment(callback)
catchAll: (callback) -> super Meteor.bindEnvironment(callback)
class RocketChatAdapter extends Hubot.Adapter
# Public: Raw method for sending data back to the chat source. Extend this.
#
# envelope - A Object with message, room and user details.
# strings - One or more Strings for each message to send.
#
# Returns nothing.
send: (envelope, strings...) ->
sendHelper @robot, envelope, strings, (string) =>
console.log "send #{envelope.rid}: #{string} (#{envelope.u.username})" if DEBUG
return @priv envelope, string if envelope.message.private
Meteor.call "sendMessage",
u:
username: "rocketbot"
msg: string
rid: envelope.rid
# Public: Raw method for sending emote data back to the chat source.
#
# envelope - A Object with message, room and user details.
# strings - One or more Strings for each message to send.
#
# Returns nothing.
emote: (envelope, strings...) ->
sendHelper @robot, envelope, strings, (string) =>
console.log "emote #{envelope.rid}: #{string} (#{envelope.u.username})" if DEBUG
return @priv envelope, "*** #{string} ***" if envelope.message.private
Meteor.call "sendMessage",
u:
username: "rocketbot"
msg: string
rid: envelope.rid
action: true
# Priv: our extension -- send a PM to user
priv: (envelope, strings...) ->
sendHelper @robot, envelope, strings, (string) ->
console.log "priv #{envelope.rid}: #{string} (#{envelope.u.username})" if DEBUG
Meteor.call "sendMessage",
u:
username: "rocketbot"
to: "#{envelope.u.username}"
msg: string
rid: envelope.rid
# Public: Raw method for building a reply and sending it back to the chat
# source. Extend this.
#
# envelope - A Object with message, room and user details.
# strings - One or more Strings for each reply to send.
#
# Returns nothing.
reply: (envelope, strings...) ->
if envelope.message.private
@priv envelope, strings...
else
@send envelope, strings.map((str) -> "#{envelope.u.username}: #{str}")...
# Public: Raw method for setting a topic on the chat source. Extend this.
#
# envelope - A Object with message, room and user details.
# strings - One more more Strings to set as the topic.
#
# Returns nothing.
topic: (envelope, strings...) ->
# Public: Raw method for playing a sound in the chat source. Extend this.
#
# envelope - A Object with message, room and user details.
# strings - One or more strings for each play message to send.
#
# Returns nothing
play: (envelope, strings...) ->
# Public: Raw method for invoking the bot to run. Extend this.
#
# Returns nothing.
run: ->
# Public: Raw method for shutting the bot down. Extend this.
#
# Returns nothing.
close: ->
class RocketBotReceiver
constructor: (message) ->
RocketBotUser = new Hubot.User(message.u.username, rid: message.rid)
RocketBotTextMessage = new Hubot.TextMessage(RocketBotUser, message.msg, message._id)
RocketBot.adapter.receive RocketBotTextMessage
console.log 'message: ', message if DEBUG
console.log 'RocketBot: ', RocketBot if DEBUG
return message
sendHelper = Meteor.bindEnvironment (robot, envelope, strings, map) ->
while strings.length > 0
string = strings.shift()
if typeof(string) == 'function'
string()
else
try
map(string)
catch err
console.error "Hubot error: #{err}" if DEBUG
robot.logger.error "RocketChat send error: #{err}"
RocketBot = new Robot null, null, false, 'rocketbot'
RocketBot.alias = 'bot'
RocketBot.adapter = new RocketChatAdapter RocketBot
HubotScripts(RocketBot)
RocketChat.callbacks.add 'afterSaveMessage', RocketBotReceiver, RocketChat.callbacks.priority.LOW
# Meteor.startup ->
# console.log RocketBot;
# # what's (the regexp for) my name?
# robot.respond /(?:)/, -> false
# mynameRE = robot.listeners.pop().regex
# # register scripts
# HubotScripts(robot)
# Object.keys(share.hubot).forEach (scriptName) ->
# console.log "Loading hubot script: #{scriptName}"
# share.hubot[scriptName](robot)
# # register our nick
# n = Meteor.call 'newNick', {name: 'rocketbot'}
# Meteor.call 'setTag', {type:'nicks', object:n._id, name:'Gravatar', value:'codex@printf.net', who:n.canon}
# # register our presence in general chat
# keepalive = -> Meteor.call 'setPresence',
# u:
# username: 'rocketbot'
# rid: '57om6EQCcFami9wuT'
# present: true
# foreground: true
# keepalive()
# Meteor.setInterval keepalive, 30*1000 # every 30s refresh presence
# # listen to the chat room, ignoring messages sent before we startup
# startup = true
# ChatMessage.find({}).observe
# added: (message) ->
# return if startup
# return if message.u.username is "rocketbot" or message.u.username is ""
# return if message.system or message.action or message.oplog or message.bodyIsHtml
# console.log "Received from #{message.u.username} in #{message.rid}: #{message.body}"\
# if DEBUG
# user = new Hubot.User(message.u.username, room: message.rid)
# tm = new Hubot.TextMessage(user, message.body, message._id)
# tm.private = message.to?
# # if private, ensure it's treated as a direct address
# if tm.private and not mynameRE.test(tm.text)
# tm.text = "#{robot.name} #{tm.text}"
# adapter.receive tm
# startup = false
# Meteor.call "sendMessage",
# rid: '57om6EQCcFami9wuT'
# msg: 'wakes up'
# u:
# username: "rocketbot"
# action: true

@ -0,0 +1,32 @@
Package.describe({
name: 'rocketchat:hubot',
version: '0.0.1',
summary: 'Package hubot for Meteor server',
git: ''
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use([
'coffeescript',
'rocketchat:lib@0.0.1'
]);
api.addFiles('hubot.coffee', ['server']);
api.export('Hubot', ['server']);
api.export('HubotScripts', ['server']);
api.export('RocketBot', ['server']);
api.export('RocketBotReceiver', ['server']);
api.export('RocketChatAdapter', ['server']);
});
Npm.depends({
"coffee-script": "1.9.3",
"codex-blackboard-hubot-scripts": "https://github.com/cscott/codex-blackboard-hubot-scripts/tarball/f57c178a2faee9b36d07a7905c29093b9824e0b0",
"hubot": "2.13.1"
});
Package.onTest(function(api) {});

@ -5,14 +5,22 @@
class Markdown
constructor: (message) ->
msg = message.html or ''
# Process MD like for strong, italic and strike
msg = msg.replace(/\*([^*]+)\*/g, '<strong>$1</strong>')
msg = msg.replace(/\_([^_]+)\_/g, '<i>$1</i>')
msg = msg.replace(/\~{1,2}([^~]+)\~{1,2}/g, '<strike>$1</strike>')
if _.trim message.html
msg = message.html
# Process MD like for strong, italic and strike
msg = msg.replace(/(\ |^)\*([^*]+)\*(\ |$)/gm, '$1<strong>$2</strong>$3')
msg = msg.replace(/(\ |^)\_([^_]+)\_(\ |$)/gm, '$1<em>$2</em>$3')
msg = msg.replace(/(\ |^)\`([^`]+)\`(\ |$)/gm, '$1<code class="inline">$2</code>$3')
msg = msg.replace(/(\ |^)\~{1,2}([^~]+)\~{1,2}(\ |$)/gm, '$1<strike>$2</strike>$3')
msg = msg.replace(/^&gt;(.*)$/gm, '<q>$1</q>')
message.html = msg
console.log 'Markdown', message if window.rocketDebug
message.html = msg
return message
RocketChat.callbacks.add 'beforeSaveMessage', Markdown, RocketChat.callbacks.priority.LOW
RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.LOW

@ -11,4 +11,4 @@ class Me
message.html = '_' + message.html.replace('/me ','') + '_'
return message
RocketChat.callbacks.add 'beforeSaveMessage', Me
RocketChat.callbacks.add 'renderMessage', Me

@ -20,4 +20,4 @@ class MentionsClient
message.html = msg
return message
RocketChat.callbacks.add 'beforeSaveMessage', MentionsClient
RocketChat.callbacks.add 'renderMessage', MentionsClient

@ -13,8 +13,8 @@ Package.onUse(function(api) {
'rocketchat:lib@0.0.1'
]);
api.addFiles('client.coffee', 'client');
api.addFiles('server.coffee', 'server');
api.addFiles('client.coffee', 'client');
});
Package.onTest(function(api) {

@ -0,0 +1,21 @@
Package.describe({
name: 'rocketchat:tmpembed',
version: '0.0.1',
summary: 'Message pre-processor that handles embedding of images and maps',
git: ''
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use([
'coffeescript',
'rocketchat:lib@0.0.1'
]);
api.addFiles('tmpembed.coffee', ['server','client']);
});
Package.onTest(function(api) {
});

@ -0,0 +1,29 @@
###
# ObjEmbedder is a temporary image and map embedder for bots development
# @param {Object} msg - The message object
# to be replaced by proper implementation in 1.0
###
class ObjEmbedder
constructor: (message) ->
console.log "ObjEmbedder constructor" if window.rocketDebug
if _.trim message.msg
console.log "ObjEmbedder trim" if window.rocketDebug
picmatch = message.msg.match(/^https?:\/\/(?:[a-z0-9\-]+\.)+[a-z0-9]{2,6}(?:\/[^\/#?]+)+\.(?:jpe?g|gif|png)$/i)
if picmatch?
# inline style to limit code pollution
console.log "ObjEmbedder picmatch" if window.rocketDebug
message.html = "<img style='width:400px;height:auto;' src='" + message.msg + "'></img>"
else
mapmatch = message.msg.match(/^https?\:\/\/maps\.(google|googleapis)\.[a-z]+\/maps\/api.*format=png$/i)
if mapmatch?
console.log "ObjEmbedder mapmatch" if window.rocketDebug
message.html = "<img style='width:400px;height:auto;' src='" + message.msg + "'></img>"
# end of temporary pre-1.0 image embed
return message
RocketChat.callbacks.add 'renderMessage', ObjEmbedder, RocketChat.callbacks.priority.HIGH

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -8,13 +8,16 @@ Meteor.methods
if not room
return false
# console.log '[methods] sendMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments
console.log '[methods] sendMessage -> '.green, 'userId:', Meteor.userId(), 'arguments:', arguments
message.u = Meteor.users.findOne Meteor.userId(), fields: username: 1
message.ts = new Date()
message.u = Meteor.users.findOne Meteor.userId(), fields: username: 1
message.html = message.msg
if _.trim(message.html) isnt ''
message.html = _.escapeHTML message.html
message = RocketChat.callbacks.run 'beforeSaveMessage', message
message.html = message.html.replace /\n/gm, '<br/>'
###
Defer other updated as their return is not interesting to the user
@ -113,3 +116,10 @@ Meteor.methods
$unset:
t: 1
expireAt: 1
Meteor.defer ->
message._id = Random.id()
RocketChat.callbacks.run 'afterSaveMessage', message

Loading…
Cancel
Save