diff --git a/.meteor/packages b/.meteor/packages index 7121f27ba09e..191db1dbd7bb 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -45,3 +45,7 @@ percolate:migrations underscorestring:underscore.string meteorhacks:kadira yasaricli:slugify +jparker:gravatar +http +cfs:filesystem +cfs:standard-packages diff --git a/.meteor/versions b/.meteor/versions index 77aef5ad40b9..7b3235323a35 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -13,7 +13,23 @@ blaze@2.1.2 blaze-tools@1.0.3 boilerplate-generator@1.0.3 callback-hook@1.0.3 +cfs:access-point@0.1.49 +cfs:base-package@0.0.30 +cfs:collection@0.5.5 +cfs:collection-filters@0.2.4 +cfs:data-man@0.0.6 +cfs:file@0.1.17 +cfs:filesystem@0.1.2 cfs:http-methods@0.0.29 +cfs:http-publish@0.0.13 +cfs:power-queue@0.9.11 +cfs:reactive-list@0.0.9 +cfs:reactive-property@0.0.4 +cfs:standard-packages@0.5.9 +cfs:storage-adapter@0.2.2 +cfs:tempstore@0.1.5 +cfs:upload-http@0.0.20 +cfs:worker@0.1.4 check@1.0.5 chrismbeckett:toastr@2.1.0 coffeescript@1.0.6 @@ -83,6 +99,7 @@ ordered-dict@1.0.3 percolate:migrations@0.7.5 percolatestudio:synced-cron@1.1.0 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 diff --git a/client/routes/router.coffee b/client/routes/router.coffee index d63a89690465..3a77ba6d8026 100644 --- a/client/routes/router.coffee +++ b/client/routes/router.coffee @@ -29,6 +29,10 @@ Router.onBeforeAction -> this.layout('usernameLayout') return this.render('usernamePrompt') + if Meteor.userId()? and not Meteor.user().avatarOrigin? + this.layout('usernameLayout') + return this.render('avatarPrompt') + this.next() , { except: ['login'] diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index bdfb1e371923..a01fef8d9b0a 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2675,6 +2675,47 @@ a.github-fork { } } +.avatar-suggestion-item { + height: 80px; + margin: 10px 0px; + text-align: left; + + > div { + height: 80px; + width: 80px; + background-size: cover; + display: inline-block; + border: 1px solid #DDD; + font-size: 80px; + text-align: center; + line-height: 80px; + background-color: #EEE; + color: #CCC; + &.question-mark:before { + content: "?"; + position: absolute; + left: 0; + width: 80px; + } + } + button { + display: inline-block; + top: -35px; + } + input[type=file] { + position: absolute !important; + width: 100%; + top: 0; + left: 0; + height: 100%; + opacity: 0; + z-index: 10000; + * { + cursor: pointer; + } + } +} + @media all and(max-width: 1100px) { #rocket-chat { .flex-opened { diff --git a/client/views/avatar/avatar.coffee b/client/views/avatar/avatar.coffee new file mode 100644 index 000000000000..7580440909ea --- /dev/null +++ b/client/views/avatar/avatar.coffee @@ -0,0 +1,53 @@ +Template.avatarPrompt.onCreated -> + self = this + self.suggestions = new ReactiveVar + self.upload = new ReactiveVar + + self.getSuggestions = -> + self.suggestions.set undefined + Meteor.call 'getAvatarSuggestion', (error, avatars) -> + self.suggestions.set + ready: true + avatars: avatars + + self.getSuggestions() + + +Template.avatarPrompt.helpers + suggestions: -> + return Template.instance().suggestions.get() + + upload: -> + return Template.instance().upload.get() + + +Template.avatarPrompt.events + 'click .select-service': (e) -> + Meteor.call 'setAvatarFromService', this.blob, this.service, -> + console.log arguments + + 'click .login-with-service': (event, template) -> + loginWithService = "loginWith#{_.capitalize(this)}" + + serviceConfig = {} + + Meteor[loginWithService] serviceConfig, (error) -> + if error?.error is 'github-no-public-email' + alert t("loginServices.github_no_public_email") + return + + console.log error + if error? + toastr.error error.message + return + + template.getSuggestions() + + 'change .myFileInput': (event, template) -> + FS.Utility.eachFile event, (blob) -> + reader = new FileReader() + reader.readAsDataURL(blob) + reader.onloadend = -> + template.upload.set + service: 'upload' + blob: reader.result diff --git a/client/views/avatar/avatar.html b/client/views/avatar/avatar.html new file mode 100644 index 000000000000..22cac8b4c9ff --- /dev/null +++ b/client/views/avatar/avatar.html @@ -0,0 +1,74 @@ + + + + + diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 0d32ed6de46e..5aa0345a91d8 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -149,5 +149,12 @@ }, "error": { "Not_found_or_not_allowed": "Not Found or Not Allowed" + }, + "avatar": { + "Use_service_avatar": "Use %s avatar", + "Login_with": "Login with %s", + "Select_an_avatar": "Select an avatar", + "Use_uploaded_avatar": "Use uploaded avatar", + "Select_file": "Select file" } } diff --git a/i18n/pt.i18n.json b/i18n/pt.i18n.json index 08cc1369f793..105cedb160d0 100644 --- a/i18n/pt.i18n.json +++ b/i18n/pt.i18n.json @@ -149,5 +149,12 @@ }, "error": { "Not_found_or_not_allowed": "Não encontrado ou não permitido" + }, + "avatar": { + "Use_service_avatar": "Use o avatar de %s", + "Login_with": "Login com %s", + "Select_an_avatar": "Selecione um avatar", + "Use_uploaded_avatar": "Use o avatar de upload", + "Select_file": "Selecione um arquivo" } } diff --git a/lib/file.coffee b/lib/file.coffee new file mode 100644 index 000000000000..589f03e744de --- /dev/null +++ b/lib/file.coffee @@ -0,0 +1,40 @@ +uploadPath = "~/uploads" + +store = new FS.Store.FileSystem "avatars", + path: uploadPath + fileKeyMaker: (fileObj) -> + filename = fileObj.name() + filenameInStore = fileObj.name({store: 'avatars'}) + + return filenameInStore || filename + +@Avatars = new FS.Collection "avatars", + stores: [store] + +@Avatars.allow + insert: -> + return true + update: -> + return true + download: -> + return true + +Meteor.startup -> + if Meteor.isServer + FS.HTTP.mount ['/avatar/:filename'], -> + self = this + opts = FS.Utility.extend({}, self.query || {}, self.params || {}) + + collectionName = opts.collectionName + + collection = FS._collections['avatars'] + + file = if collection? then collection.findOne({ "copies.avatars.key": opts.filename }) else null + + return { + collection: collection + file: file + storeName: 'avatars' + download: opts.download + filename: opts.filename + } diff --git a/server/methods/getAvatarSuggestion.coffee b/server/methods/getAvatarSuggestion.coffee new file mode 100644 index 000000000000..dcb169577f1d --- /dev/null +++ b/server/methods/getAvatarSuggestion.coffee @@ -0,0 +1,43 @@ +Meteor.methods + getAvatarSuggestion: -> + if not Meteor.userId() + throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado' + + user = Meteor.user() + + avatars = [] + + if user.services.facebook?.id? + avatars.push + service: 'facebook' + url: "https://graph.facebook.com/#{user.services.facebook.id}/picture?type=large" + + if user.services.google?.picture? + avatars.push + service: 'google' + url: user.services.google.picture + + if user.services.github?.username? + avatars.push + service: 'github' + url: "https://avatars.githubusercontent.com/#{user.services.github.username}?s=200" + + if user.emails?.length > 0 + for email in user.emails when email.verified is true + avatars.push + service: 'gravatar' + url: Gravatar.imageUrl email.address + + validAvatars = {} + for avatar in avatars + try + result = HTTP.get avatar.url, npmRequestOptions: {encoding: null} + if result.statusCode is 200 + blob = "data:#{result.headers['content-type']};base64," + blob += Buffer(result.content, 'binary').toString('base64') + avatar.blob = blob + validAvatars[avatar.service] = avatar + catch e + # ... + + return validAvatars diff --git a/server/methods/setAvatarFromService.coffee b/server/methods/setAvatarFromService.coffee new file mode 100644 index 000000000000..7f851d9bbc4e --- /dev/null +++ b/server/methods/setAvatarFromService.coffee @@ -0,0 +1,14 @@ +Meteor.methods + setAvatarFromService: (image, service) -> + if not Meteor.userId() + throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado' + + user = Meteor.user() + + file = new FS.File image + file.attachData image, -> + file.name user.username + + Avatars.insert file, (err, fileObj) -> + Meteor.users.update {_id: user._id}, {$set: {avatarOrigin: service}} + diff --git a/server/publications.coffee b/server/publications.coffee index 1cc7d27137d5..0bbf5a4c5e19 100644 --- a/server/publications.coffee +++ b/server/publications.coffee @@ -12,6 +12,7 @@ Meteor.publish 'userData', -> status: 1 statusDefault: 1 statusConnection: 1 + avatarOrigin: 1 emails: 1 'services.facebook.id': 1 'services.google.picture': 1