diff --git a/.meteor/packages b/.meteor/packages index a9a3ac0132f34..4ed7a2422855c 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -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 \ No newline at end of file diff --git a/.meteor/versions b/.meteor/versions index 2f06a968c5592..86bc6a68bc29b 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -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 diff --git a/client/methods/sendMessage.coffee b/client/methods/sendMessage.coffee index e40a38c820d0c..877477f6e07e2 100644 --- a/client/methods/sendMessage.coffee +++ b/client/methods/sendMessage.coffee @@ -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, '
' - console.log message + message.html = message.html.replace /\n/gm, '
' ChatMessage.upsert rid: message.rid diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index d938abeca1c05..a9f31c0f7c189 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -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%; diff --git a/client/stylesheets/rtl.less b/client/stylesheets/rtl.less new file mode 100644 index 0000000000000..8e429821b081a --- /dev/null +++ b/client/stylesheets/rtl.less @@ -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); + } +} diff --git a/client/views/app/chatMessageDashboard.coffee b/client/views/app/chatMessageDashboard.coffee index 27ef90a85d7bb..639ded8c417f9 100644 --- a/client/views/app/chatMessageDashboard.coffee +++ b/client/views/app/chatMessageDashboard.coffee @@ -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, '
' + 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 { diff --git a/client/views/app/chatMessageDashboard.html b/client/views/app/chatMessageDashboard.html index 0c9f1e5efc955..c29ed51a1ae39 100644 --- a/client/views/app/chatMessageDashboard.html +++ b/client/views/app/chatMessageDashboard.html @@ -4,7 +4,7 @@ {{messageDate data.ts}} {{/if}} -
  • +
  • {{#with data}} {{#if isSystemMessage}}

    {{{message}}}

    @@ -25,7 +25,7 @@ {{#if isEditing}}
    {{> messagePopupConfig getPupupConfig}} - +
    {{else}} {{#if ../single}} @@ -41,8 +41,8 @@ {{/if}} {{/if}} -
    - {{{html}}} +
    + {{{renderMessage}}}
    {{/if}} {{/if}} diff --git a/client/views/app/chatWindowDashboard.html b/client/views/app/chatWindowDashboard.html index cb09d101e9df7..c4e683d9966c3 100644 --- a/client/views/app/chatWindowDashboard.html +++ b/client/views/app/chatWindowDashboard.html @@ -13,7 +13,7 @@

    {{roomName}} {{#if canEditName}} - + {{/if}}

    @@ -57,9 +57,8 @@

    - {{> messagePopupConfig getPupupConfig}} - +
    @@ -80,6 +79,14 @@

    {{/if}} {{/with}}

    +
    diff --git a/client/views/app/layout.coffee b/client/views/app/layout.coffee index 553ea951a4790..962285104f24f 100644 --- a/client/views/app/layout.coffee +++ b/client/views/app/layout.coffee @@ -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") diff --git a/client/views/app/privateHistory.html b/client/views/app/privateHistory.html index 55a7c8fd7c98d..901274c54c247 100644 --- a/client/views/app/privateHistory.html +++ b/client/views/app/privateHistory.html @@ -10,7 +10,7 @@

    diff --git a/client/views/app/sideNav/createChannelFlex.html b/client/views/app/sideNav/createChannelFlex.html index 50128bce81d58..8dbdb66af91ab 100644 --- a/client/views/app/sideNav/createChannelFlex.html +++ b/client/views/app/sideNav/createChannelFlex.html @@ -9,7 +9,7 @@

    {{_ "chatRooms.Channels"}}

    {{_ "chatRooms.Create_new_channel" }}

    - +
    diff --git a/client/views/app/sideNav/privateGroupsFlex.html b/client/views/app/sideNav/privateGroupsFlex.html index fe9a16817fc74..0cd39bc2d2d68 100644 --- a/client/views/app/sideNav/privateGroupsFlex.html +++ b/client/views/app/sideNav/privateGroupsFlex.html @@ -9,7 +9,7 @@

    {{_ "chatRooms.Private_Groups"}}

    Create a new private group

    - +
    @@ -34,4 +34,4 @@

    Create a new private group

    - \ No newline at end of file + diff --git a/client/views/login/form.html b/client/views/login/form.html index 3f4643f4f93cf..9f729cb9a5842 100644 --- a/client/views/login/form.html +++ b/client/views/login/form.html @@ -10,7 +10,7 @@

    {{_ "login.Enter_info"}}

    {{/if}}
    - +
    diff --git a/client/views/username/prompt.html b/client/views/username/prompt.html index 7ba513529e6a6..ba81c004f7b7c 100644 --- a/client/views/username/prompt.html +++ b/client/views/username/prompt.html @@ -23,7 +23,7 @@

    {{_ "usernameRegistration.Username_title"}}

    {{#if username.ready}} - + {{else}} diff --git a/packages/rocketchat-autolinker/autolinker.coffee b/packages/rocketchat-autolinker/autolinker.coffee index b07f24796213d..6dac64a854794 100644 --- a/packages/rocketchat-autolinker/autolinker.coffee +++ b/packages/rocketchat-autolinker/autolinker.coffee @@ -10,4 +10,4 @@ class AutoLinker return message -RocketChat.callbacks.add 'beforeSaveMessage', AutoLinker +RocketChat.callbacks.add 'renderMessage', AutoLinker diff --git a/packages/rocketchat-emojione/emojione.coffee b/packages/rocketchat-emojione/emojione.coffee index d03163aea9d9b..492dc943e8acc 100644 --- a/packages/rocketchat-emojione/emojione.coffee +++ b/packages/rocketchat-emojione/emojione.coffee @@ -10,4 +10,4 @@ class Emojione return message -RocketChat.callbacks.add 'beforeSaveMessage', Emojione, RocketChat.callbacks.priority.LOW \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', Emojione, RocketChat.callbacks.priority.LOW \ No newline at end of file diff --git a/packages/rocketchat-file/package.js b/packages/rocketchat-file/package.js index e6ad9edd950bf..7ed4a9d40ff39 100644 --- a/packages/rocketchat-file/package.js +++ b/packages/rocketchat-file/package.js @@ -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) { }); diff --git a/packages/rocketchat-highlight/highlight.coffee b/packages/rocketchat-highlight/highlight.coffee index 4e987d9c80801..27b00da7e62c8 100644 --- a/packages/rocketchat-highlight/highlight.coffee +++ b/packages/rocketchat-highlight/highlight.coffee @@ -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] = "
    " + result.value + "
    " else # Escape html and fix line breaks for non code blocks - part = _.escapeHTML part - part = part.replace /\n/g, '
    ' msgParts[index] = part # Re-mount message @@ -35,4 +33,4 @@ class Highlight return message -RocketChat.callbacks.add 'beforeSaveMessage', Highlight, RocketChat.callbacks.priority.HIGH \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', Highlight, RocketChat.callbacks.priority.HIGH diff --git a/packages/rocketchat-hubot/.npm/package/.gitignore b/packages/rocketchat-hubot/.npm/package/.gitignore new file mode 100644 index 0000000000000..3c3629e647f5d --- /dev/null +++ b/packages/rocketchat-hubot/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/rocketchat-hubot/.npm/package/README b/packages/rocketchat-hubot/.npm/package/README new file mode 100644 index 0000000000000..3d492553a438e --- /dev/null +++ b/packages/rocketchat-hubot/.npm/package/README @@ -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. diff --git a/packages/rocketchat-hubot/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-hubot/.npm/package/npm-shrinkwrap.json new file mode 100644 index 0000000000000..370832fe5fd8e --- /dev/null +++ b/packages/rocketchat-hubot/.npm/package/npm-shrinkwrap.json @@ -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" + } + } + } + } +} diff --git a/packages/rocketchat-hubot/hubot.coffee b/packages/rocketchat-hubot/hubot.coffee new file mode 100644 index 0000000000000..10cb37d54040f --- /dev/null +++ b/packages/rocketchat-hubot/hubot.coffee @@ -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 diff --git a/packages/rocketchat-hubot/package.js b/packages/rocketchat-hubot/package.js new file mode 100644 index 0000000000000..e58d9d52e85c8 --- /dev/null +++ b/packages/rocketchat-hubot/package.js @@ -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) {}); diff --git a/packages/rocketchat-markdown/markdown.coffee b/packages/rocketchat-markdown/markdown.coffee index c471f30485404..d83e780e2bc3f 100644 --- a/packages/rocketchat-markdown/markdown.coffee +++ b/packages/rocketchat-markdown/markdown.coffee @@ -5,14 +5,22 @@ class Markdown constructor: (message) -> - msg = message.html or '' - # Process MD like for strong, italic and strike - msg = msg.replace(/\*([^*]+)\*/g, '$1') - msg = msg.replace(/\_([^_]+)\_/g, '$1') - msg = msg.replace(/\~{1,2}([^~]+)\~{1,2}/g, '$1') + if _.trim message.html + + msg = message.html + + # Process MD like for strong, italic and strike + msg = msg.replace(/(\ |^)\*([^*]+)\*(\ |$)/gm, '$1$2$3') + msg = msg.replace(/(\ |^)\_([^_]+)\_(\ |$)/gm, '$1$2$3') + msg = msg.replace(/(\ |^)\`([^`]+)\`(\ |$)/gm, '$1$2$3') + msg = msg.replace(/(\ |^)\~{1,2}([^~]+)\~{1,2}(\ |$)/gm, '$1$2$3') + msg = msg.replace(/^>(.*)$/gm, '$1') + + message.html = msg + + console.log 'Markdown', message if window.rocketDebug - message.html = msg return message -RocketChat.callbacks.add 'beforeSaveMessage', Markdown, RocketChat.callbacks.priority.LOW \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', Markdown, RocketChat.callbacks.priority.LOW diff --git a/packages/rocketchat-me/me.coffee b/packages/rocketchat-me/me.coffee index 3a80168a5186f..965b2b6d296cd 100644 --- a/packages/rocketchat-me/me.coffee +++ b/packages/rocketchat-me/me.coffee @@ -11,4 +11,4 @@ class Me message.html = '_' + message.html.replace('/me ','') + '_' return message -RocketChat.callbacks.add 'beforeSaveMessage', Me +RocketChat.callbacks.add 'renderMessage', Me diff --git a/packages/rocketchat-mentions/client.coffee b/packages/rocketchat-mentions/client.coffee index fdd889c5678c4..c0307b507ad64 100644 --- a/packages/rocketchat-mentions/client.coffee +++ b/packages/rocketchat-mentions/client.coffee @@ -20,4 +20,4 @@ class MentionsClient message.html = msg return message -RocketChat.callbacks.add 'beforeSaveMessage', MentionsClient \ No newline at end of file +RocketChat.callbacks.add 'renderMessage', MentionsClient \ No newline at end of file diff --git a/packages/rocketchat-mentions/package.js b/packages/rocketchat-mentions/package.js index f2b4100101ca8..51266c3fd9c04 100644 --- a/packages/rocketchat-mentions/package.js +++ b/packages/rocketchat-mentions/package.js @@ -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) { diff --git a/packages/rocketchat-tmpembed/package.js b/packages/rocketchat-tmpembed/package.js new file mode 100644 index 0000000000000..e15a73497b9bd --- /dev/null +++ b/packages/rocketchat-tmpembed/package.js @@ -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) { + +}); diff --git a/packages/rocketchat-tmpembed/tmpembed.coffee b/packages/rocketchat-tmpembed/tmpembed.coffee new file mode 100644 index 0000000000000..f3e52a6e3005c --- /dev/null +++ b/packages/rocketchat-tmpembed/tmpembed.coffee @@ -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 = "" + + 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 = "" + + # end of temporary pre-1.0 image embed + return message + +RocketChat.callbacks.add 'renderMessage', ObjEmbedder, RocketChat.callbacks.priority.HIGH diff --git a/public/images/logo/512x512.jpg b/public/images/logo/512x512.jpg new file mode 100644 index 0000000000000..454376c0d331a Binary files /dev/null and b/public/images/logo/512x512.jpg differ diff --git a/server/methods/sendMessage.coffee b/server/methods/sendMessage.coffee index 54c126f46221c..f9884d25e40c9 100644 --- a/server/methods/sendMessage.coffee +++ b/server/methods/sendMessage.coffee @@ -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, '
    ' ### 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 + +