FIX: profile picture selector
This commit is contained in:
parent
6437cd0341
commit
0c58f08207
|
@ -1,3 +1,4 @@
|
|||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import UploadMixin from "discourse/mixins/upload";
|
||||
|
||||
export default Em.Component.extend(UploadMixin, {
|
||||
|
@ -5,21 +6,23 @@ export default Em.Component.extend(UploadMixin, {
|
|||
tagName: "span",
|
||||
imageIsNotASquare: false,
|
||||
|
||||
uploadButtonText: function() {
|
||||
return this.get("uploading") ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture");
|
||||
}.property("uploading"),
|
||||
@computed("uploading")
|
||||
uploadButtonText(uploading) {
|
||||
return uploading ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture");
|
||||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.setProperties({
|
||||
imageIsNotASquare: upload.width !== upload.height,
|
||||
uploadedAvatarTemplate: upload.url,
|
||||
custom_avatar_upload_id: upload.id,
|
||||
uploadedAvatarId: upload.id,
|
||||
});
|
||||
|
||||
this.sendAction("done");
|
||||
},
|
||||
|
||||
data: function() {
|
||||
return { user_id: this.get("user_id") };
|
||||
}.property("user_id")
|
||||
@computed("user_id")
|
||||
data(user_id) {
|
||||
return { user_id };
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
uploadedAvatarTemplate: null,
|
||||
saveDisabled: Em.computed.alias("uploading"),
|
||||
hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'custom_avatar_upload_id'),
|
||||
|
||||
selectedUploadId: function() {
|
||||
switch (this.get("selected")) {
|
||||
case "system": return this.get("system_avatar_upload_id");
|
||||
case "gravatar": return this.get("gravatar_avatar_upload_id");
|
||||
default: return this.get("custom_avatar_upload_id");
|
||||
@computed("selected", "system_avatar_upload_id", "gravatar_avatar_upload_id", "custom_avatar_upload_id")
|
||||
selectedUploadId(selected, system, gravatar, custom) {
|
||||
switch (selected) {
|
||||
case "system": return system;
|
||||
case "gravatar": return gravatar;
|
||||
default: return custom;
|
||||
}
|
||||
}.property('selected', 'system_avatar_upload_id', 'gravatar_avatar_upload_id', 'custom_avatar_upload_id'),
|
||||
},
|
||||
|
||||
allowImageUpload: function() {
|
||||
@computed("selected", "system_avatar_template", "gravatar_avatar_template", "custom_avatar_template")
|
||||
selectedAvatarTemplate(selected, system, gravatar, custom) {
|
||||
switch (selected) {
|
||||
case "system": return system;
|
||||
case "gravatar": return gravatar;
|
||||
default: return custom;
|
||||
}
|
||||
},
|
||||
|
||||
@computed()
|
||||
allowImageUpload() {
|
||||
return Discourse.Utilities.allowsImages();
|
||||
}.property(),
|
||||
},
|
||||
|
||||
actions: {
|
||||
useUploadedAvatar() { this.set("selected", "uploaded"); },
|
||||
|
@ -25,8 +33,11 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
refreshGravatar() {
|
||||
this.set("gravatarRefreshDisabled", true);
|
||||
return Discourse
|
||||
.ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar.json", { method: 'POST' })
|
||||
.then(result => this.set("gravatar_avatar_upload_id", result.upload_id))
|
||||
.ajax(`/user_avatar/${this.get("username")}/refresh_gravatar.json`, { method: "POST" })
|
||||
.then(result => this.setProperties({
|
||||
gravatar_avatar_template: result.gravatar_avatar_template,
|
||||
gravatar_upload_id: result.gravatar_upload_id,
|
||||
}))
|
||||
.finally(() => this.set("gravatarRefreshDisabled", false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,32 +3,27 @@ import { longDate, autoUpdatingRelativeAge, number } from 'discourse/lib/formatt
|
|||
|
||||
const safe = Handlebars.SafeString;
|
||||
|
||||
Em.Handlebars.helper('bound-avatar', function(user, size) {
|
||||
Em.Handlebars.helper('bound-avatar', (user, size) => {
|
||||
if (Em.isEmpty(user)) {
|
||||
return new safe("<div class='avatar-placeholder'></div>");
|
||||
}
|
||||
|
||||
const avatar = Em.get(user, 'avatar_template');
|
||||
|
||||
return new safe(Discourse.Utilities.avatarImg({ size: size, avatarTemplate: avatar }));
|
||||
}, 'username', 'avatar_template');
|
||||
|
||||
/*
|
||||
* Used when we only have a template
|
||||
*/
|
||||
Em.Handlebars.helper('bound-avatar-template', function(at, size) {
|
||||
Em.Handlebars.helper('bound-avatar-template', (at, size) => {
|
||||
return new safe(Discourse.Utilities.avatarImg({ size: size, avatarTemplate: at }));
|
||||
});
|
||||
|
||||
registerUnbound('raw-date', function(dt) {
|
||||
return longDate(new Date(dt));
|
||||
});
|
||||
registerUnbound('raw-date', dt => longDate(new Date(dt)));
|
||||
|
||||
registerUnbound('age-with-tooltip', function(dt) {
|
||||
return new safe(autoUpdatingRelativeAge(new Date(dt), {title: true}));
|
||||
});
|
||||
registerUnbound('age-with-tooltip', dt => new safe(autoUpdatingRelativeAge(new Date(dt), {title: true})));
|
||||
|
||||
registerUnbound('number', function(orig, params) {
|
||||
registerUnbound('number', (orig, params) => {
|
||||
orig = parseInt(orig, 10);
|
||||
if (isNaN(orig)) { orig = 0; }
|
||||
|
||||
|
|
|
@ -256,47 +256,33 @@ const User = RestModel.extend({
|
|||
});
|
||||
},
|
||||
|
||||
/*
|
||||
Change avatar selection
|
||||
*/
|
||||
pickAvatar(uploadId) {
|
||||
pickAvatar(upload_id, avatar_template) {
|
||||
return Discourse.ajax(`/users/${this.get("username_lower")}/preferences/avatar/pick`, {
|
||||
type: 'PUT',
|
||||
data: { upload_id: uploadId }
|
||||
}).then(() => this.set('uploaded_avatar_id', uploadId));
|
||||
data: { upload_id }
|
||||
}).then(() => this.setProperties({
|
||||
avatar_template,
|
||||
uploaded_avatar_id: upload_id
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
Determines whether the current user is allowed to upload a file.
|
||||
|
||||
@method isAllowedToUploadAFile
|
||||
@param {String} type The type of the upload (image, attachment)
|
||||
@returns true if the current user is allowed to upload a file
|
||||
**/
|
||||
isAllowedToUploadAFile(type) {
|
||||
return this.get('staff') ||
|
||||
this.get('trust_level') > 0 ||
|
||||
Discourse.SiteSettings['newuser_max_' + type + 's'] > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
Invite a user to the site
|
||||
|
||||
@method createInvite
|
||||
@param {String} email The email address of the user to invite to the site
|
||||
@returns {Promise} the result of the server call
|
||||
**/
|
||||
createInvite(email, groupNames) {
|
||||
createInvite(email, group_names) {
|
||||
return Discourse.ajax('/invites', {
|
||||
type: 'POST',
|
||||
data: {email: email, group_names: groupNames}
|
||||
data: { email, group_names }
|
||||
});
|
||||
},
|
||||
|
||||
generateInviteLink(email, groupNames, topicId) {
|
||||
generateInviteLink(email, group_names, topic_id) {
|
||||
return Discourse.ajax('/invites/link', {
|
||||
type: 'POST',
|
||||
data: {email: email, group_names: groupNames, topic_id: topicId}
|
||||
data: { email, group_names, topic_id }
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -18,50 +18,51 @@ export default RestrictedUserRoute.extend({
|
|||
showModal('avatar-selector');
|
||||
|
||||
// all the properties needed for displaying the avatar selector modal
|
||||
const controller = this.controllerFor('avatar-selector'),
|
||||
props = this.modelFor('user').getProperties(
|
||||
const props = this.modelFor('user').getProperties(
|
||||
'id',
|
||||
'email',
|
||||
'username',
|
||||
'uploaded_avatar_id',
|
||||
'avatar_template',
|
||||
'system_avatar_template',
|
||||
'gravatar_avatar_template',
|
||||
'custom_avatar_template',
|
||||
'system_avatar_upload_id',
|
||||
'gravatar_avatar_upload_id',
|
||||
'custom_avatar_upload_id'
|
||||
);
|
||||
|
||||
switch (props.uploaded_avatar_id) {
|
||||
case props.system_avatar_upload_id:
|
||||
switch (props.avatar_template) {
|
||||
case props.system_avatar_template:
|
||||
props.selected = "system";
|
||||
break;
|
||||
case props.gravatar_avatar_upload_id:
|
||||
case props.gravatar_avatar_template:
|
||||
props.selected = "gravatar";
|
||||
break;
|
||||
default:
|
||||
props.selected = "uploaded";
|
||||
}
|
||||
|
||||
controller.setProperties(props);
|
||||
this.controllerFor('avatar-selector').setProperties(props);
|
||||
},
|
||||
|
||||
saveAvatarSelection() {
|
||||
const user = this.modelFor('user'),
|
||||
avatarSelector = this.controllerFor('avatar-selector');
|
||||
controller = this.controllerFor('avatar-selector'),
|
||||
selectedUploadId = controller.get("selectedUploadId"),
|
||||
selectedAvatarTemplate = controller.get("selectedAvatarTemplate");
|
||||
|
||||
// sends the information to the server if it has changed
|
||||
if (avatarSelector.get('selectedUploadId') !== user.get('uploaded_avatar_id')) {
|
||||
user.pickAvatar(avatarSelector.get('selectedUploadId'))
|
||||
.then(() => {
|
||||
user.setProperties(avatarSelector.getProperties(
|
||||
'system_avatar_upload_id',
|
||||
'gravatar_avatar_upload_id',
|
||||
'custom_avatar_upload_id'
|
||||
));
|
||||
bootbox.alert(I18n.t("user.change_avatar.cache_notice"));
|
||||
});
|
||||
}
|
||||
user.pickAvatar(selectedUploadId, selectedAvatarTemplate)
|
||||
.then(() => {
|
||||
user.setProperties(controller.getProperties(
|
||||
'system_avatar_template',
|
||||
'gravatar_avatar_template',
|
||||
'custom_avatar_template'
|
||||
));
|
||||
bootbox.alert(I18n.t("user.change_avatar.cache_notice"));
|
||||
});
|
||||
|
||||
// saves the data back
|
||||
avatarSelector.send('closeModal');
|
||||
controller.send('closeModal');
|
||||
},
|
||||
|
||||
}
|
||||
|
|
|
@ -2,32 +2,27 @@
|
|||
<div>
|
||||
<div>
|
||||
<input type="radio" id="system-avatar" name="avatar" value="system" {{action "useSystem"}}>
|
||||
<label class="radio" for="system-avatar">{{bound-avatar controller "large" system_avatar_upload_id}} {{{i18n 'user.change_avatar.letter_based'}}}</label>
|
||||
<label class="radio" for="system-avatar">{{bound-avatar-template system_avatar_template "large"}} {{{i18n 'user.change_avatar.letter_based'}}}</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="gravatar" name="avatar" value="gravatar" {{action "useGravatar"}}>
|
||||
<label class="radio" for="gravatar">{{bound-avatar controller "large" gravatar_avatar_upload_id}} {{{i18n 'user.change_avatar.gravatar'}}} {{email}}</label>
|
||||
<label class="radio" for="gravatar">{{bound-avatar-template gravatar_avatar_template "large"}} {{{i18n 'user.change_avatar.gravatar'}}} {{email}}</label>
|
||||
{{d-button action="refreshGravatar" title="user.change_avatar.refresh_gravatar_title" disabled=gravatarRefreshDisabled icon="refresh"}}
|
||||
</div>
|
||||
{{#if allowImageUpload}}
|
||||
<div>
|
||||
<input type="radio" id="uploaded_avatar" name="avatar" value="uploaded" {{action "useUploadedAvatar"}}>
|
||||
<label class="radio" for="uploaded_avatar">
|
||||
{{#if hasUploadedAvatar}}
|
||||
{{#if uploadedAvatarTemplate}}
|
||||
{{bound-avatar-template uploadedAvatarTemplate "large"}}
|
||||
{{else}}
|
||||
{{bound-avatar controller "large" custom_avatar_upload_id}}
|
||||
{{/if}}
|
||||
{{#if custom_avatar_template}}
|
||||
{{bound-avatar-template custom_avatar_template "large"}}
|
||||
{{i18n 'user.change_avatar.uploaded_avatar'}}
|
||||
{{else}}
|
||||
{{i18n 'user.change_avatar.uploaded_avatar_empty'}}
|
||||
{{/if}}
|
||||
</label>
|
||||
{{avatar-uploader username=username
|
||||
user_id=id
|
||||
uploadedAvatarTemplate=uploadedAvatarTemplate
|
||||
custom_avatar_upload_id=custom_avatar_upload_id
|
||||
{{avatar-uploader user_id=id
|
||||
uploadedAvatarTemplate=custom_avatar_template
|
||||
uploadedAvatarId=custom_avatar_upload_id
|
||||
uploading=uploading
|
||||
done="useUploadedAvatar"}}
|
||||
</div>
|
||||
|
@ -36,6 +31,6 @@
|
|||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
{{d-button action="saveAvatarSelection" class="btn-primary" disabled=saveDisabled label="save"}}
|
||||
{{d-button action="saveAvatarSelection" class="btn-primary" disabled=uploading label="save"}}
|
||||
<a {{action "closeModal"}}>{{i18n 'cancel'}}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { on, observes } from "ember-addons/ember-computed-decorators";
|
||||
import ModalBodyView from "discourse/views/modal-body";
|
||||
|
||||
export default ModalBodyView.extend({
|
||||
|
@ -6,11 +7,14 @@ export default ModalBodyView.extend({
|
|||
title: I18n.t('user.change_avatar.title'),
|
||||
|
||||
// *HACK* used to select the proper radio button, because {{action}} stops the default behavior
|
||||
selectedChanged: function() {
|
||||
@on("didInsertElement")
|
||||
@observes("controller.selected")
|
||||
selectedChanged() {
|
||||
Em.run.next(() => $('input:radio[name="avatar"]').val([this.get('controller.selected')]));
|
||||
}.observes('controller.selected').on("didInsertElement"),
|
||||
},
|
||||
|
||||
_focusSelectedButton: function() {
|
||||
@on("didInsertElement")
|
||||
_focusSelectedButton() {
|
||||
Em.run.next(() => $('input:radio[value="' + this.get('controller.selected') + '"]').focus());
|
||||
}.on("didInsertElement")
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,7 +13,10 @@ class UserAvatarsController < ApplicationController
|
|||
user.create_user_avatar(user_id: user.id) unless user.user_avatar
|
||||
user.user_avatar.update_gravatar!
|
||||
|
||||
render json: { upload_id: user.user_avatar.gravatar_upload_id }
|
||||
render json: {
|
||||
gravatar_upload_id: user.user_avatar.gravatar_upload_id,
|
||||
gravatar_avatar_template: User.avatar_template(user.username, user.user_avatar.gravatar_upload_id)
|
||||
}
|
||||
else
|
||||
raise Discourse::NotFound
|
||||
end
|
||||
|
|
|
@ -471,9 +471,8 @@ class User < ActiveRecord::Base
|
|||
def self.system_avatar_template(username)
|
||||
# TODO it may be worth caching this in a distributed cache, should be benched
|
||||
if SiteSetting.external_system_avatars_enabled
|
||||
color = letter_avatar_color(username)
|
||||
url = SiteSetting.external_system_avatars_url.dup
|
||||
url.gsub! "{color}", color
|
||||
url.gsub! "{color}", letter_avatar_color(username)
|
||||
url.gsub! "{username}", username
|
||||
url.gsub! "{first_letter}", username[0].downcase
|
||||
url
|
||||
|
@ -482,10 +481,6 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def letter_avatar_color
|
||||
self.class.letter_avatar_color(username)
|
||||
end
|
||||
|
||||
def self.letter_avatar_color(username)
|
||||
username = username || ""
|
||||
color = LetterAvatar::COLORS[Digest::MD5.hexdigest(username)[0...15].to_i(16) % LetterAvatar::COLORS.length]
|
||||
|
|
|
@ -93,8 +93,12 @@ class UserSerializer < BasicUserSerializer
|
|||
:watched_category_ids,
|
||||
:private_messages_stats,
|
||||
:disable_jump_reply,
|
||||
:system_avatar_upload_id,
|
||||
:system_avatar_template,
|
||||
:gravatar_avatar_upload_id,
|
||||
:gravatar_avatar_template,
|
||||
:custom_avatar_upload_id,
|
||||
:custom_avatar_template,
|
||||
:has_title_badges,
|
||||
:card_image_badge,
|
||||
:card_image_badge_id,
|
||||
|
@ -278,14 +282,32 @@ class UserSerializer < BasicUserSerializer
|
|||
UserAction.private_messages_stats(object.id, scope)
|
||||
end
|
||||
|
||||
def system_avatar_upload_id
|
||||
# should be left blank
|
||||
end
|
||||
|
||||
def system_avatar_template
|
||||
User.system_avatar_template(object.username)
|
||||
end
|
||||
|
||||
def gravatar_avatar_upload_id
|
||||
object.user_avatar.try(:gravatar_upload_id)
|
||||
end
|
||||
|
||||
def gravatar_avatar_template
|
||||
return unless gravatar_upload_id = object.user_avatar.try(:gravatar_upload_id)
|
||||
User.avatar_template(object.username, gravatar_upload_id)
|
||||
end
|
||||
|
||||
def custom_avatar_upload_id
|
||||
object.user_avatar.try(:custom_upload_id)
|
||||
end
|
||||
|
||||
def custom_avatar_template
|
||||
return unless custom_upload_id = object.user_avatar.try(:custom_upload_id)
|
||||
User.avatar_template(object.username, custom_upload_id)
|
||||
end
|
||||
|
||||
def has_title_badges
|
||||
object.badges.where(allow_title: true).count > 0
|
||||
end
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import avatarTemplate from 'discourse/lib/avatar-template';
|
||||
|
||||
module('lib:avatar-template');
|
||||
|
||||
test("avatarTemplate", function(){
|
||||
var oldCDN = Discourse.CDN;
|
||||
var oldBase = Discourse.BaseUrl;
|
||||
Discourse.BaseUrl = "frogs.com";
|
||||
|
||||
equal(avatarTemplate("sam", 1), "/user_avatar/frogs.com/sam/{size}/1.png");
|
||||
Discourse.CDN = "http://awesome.cdn.com";
|
||||
equal(avatarTemplate("sam", 1), "http://awesome.cdn.com/user_avatar/frogs.com/sam/{size}/1.png");
|
||||
Discourse.CDN = oldCDN;
|
||||
Discourse.BaseUrl = oldBase;
|
||||
});
|
||||
|
Loading…
Reference in New Issue