FIX: profile picture wasn't properly updating

This commit is contained in:
Régis Hanol 2015-03-19 19:57:07 +01:00
parent 5084e2bdf1
commit 11bf7da63c
13 changed files with 82 additions and 80 deletions

View File

@ -455,7 +455,7 @@
{{#unless anonymizeForbidden}}
{{d-button label="admin.user.anonymize"
icon="exclamation-triangle"
class="btn btn-danger"
class="btn-danger"
disabled=anonymizeForbidden
action="anonymize"}}
{{/unless}}
@ -463,7 +463,7 @@
{{#unless deleteForbidden}}
{{d-button label="admin.user.delete"
icon="exclamation-triangle"
class="btn btn-danger"
class="btn-danger"
disabled=deleteForbidden
action="destroy"}}
{{/unless}}

View File

@ -1,19 +1,19 @@
import UploadMixin from 'discourse/mixins/upload';
export default Em.Component.extend(UploadMixin, {
type: 'avatar',
tagName: 'span',
imageIsNotASquare: false,
type: 'avatar',
uploadUrl: Discourse.computed.url('username', '/users/%@/preferences/user_image'),
uploadButtonText: function() {
return this.get("uploading") ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture");
return this.get("uploading") ?
I18n.t("uploading") :
I18n.t("user.change_avatar.upload_picture");
}.property("uploading"),
uploadDone: function(data) {
var self = this;
uploadDone(data) {
// display a warning whenever the image is not a square
this.set("imageIsNotASquare", data.result.width !== data.result.height);
@ -21,13 +21,13 @@ export default Em.Component.extend(UploadMixin, {
// indeed, the server gives us back the url to the file we've just uploaded
// often, this file is not a square, so we need to crop it properly
// this will also capture the first frame of animated avatars when they're not allowed
Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(function(avatarTemplate) {
self.set("uploadedAvatarTemplate", avatarTemplate);
Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(avatarTemplate => {
this.set("uploadedAvatarTemplate", avatarTemplate);
// indicates the users is using an uploaded avatar (must happen after cropping, otherwise
// we will attempt to load an invalid avatar and cache a redirect to old one, uploadedAvatarTemplate
// trumps over custom avatar upload id)
self.set("custom_avatar_upload_id", data.result.upload_id);
this.set("custom_avatar_upload_id", data.result.upload_id);
});
// the upload is now done

View File

@ -32,5 +32,6 @@ export default Ember.Component.extend({
click() {
this.sendAction("action", this.get("actionParam"));
return false;
}
});

View File

@ -2,8 +2,10 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
import DiscourseController from 'discourse/controllers/controller';
export default DiscourseController.extend(ModalFunctionality, {
uploadedAvatarTemplate: null,
hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'custom_avatar_upload_id'),
selectedUploadId: function(){
selectedUploadId: function() {
switch (this.get("selected")) {
case "system": return this.get("system_avatar_upload_id");
case "gravatar": return this.get("gravatar_avatar_upload_id");
@ -12,18 +14,16 @@ export default DiscourseController.extend(ModalFunctionality, {
}.property('selected', 'system_avatar_upload_id', 'gravatar_avatar_upload_id', 'custom_avatar_upload_id'),
actions: {
useUploadedAvatar: function() { this.set("selected", "uploaded"); },
useGravatar: function() { this.set("selected", "gravatar"); },
useSystem: function() { this.set("selected", "system"); },
refreshGravatar: function() {
var self = this;
self.set("gravatarRefreshDisabled", true);
Discourse
.ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar", {method: 'POST'})
.then(function(result){
self.set("gravatarRefreshDisabled", false);
self.set("gravatar_avatar_upload_id", result.upload_id);
});
useUploadedAvatar() { this.set("selected", "uploaded"); },
useGravatar() { this.set("selected", "gravatar"); },
useSystem() { this.set("selected", "system"); },
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))
.finally(() => this.set("gravatarRefreshDisabled", false));
}
}

View File

@ -1,4 +1,4 @@
export default function showModal(name, model) {
export default (name, model) => {
// We use the container here because modals are like singletons
// in Discourse. Only one can be shown with a particular state.
const route = Discourse.__container__.lookup('route:application');
@ -12,5 +12,4 @@ export default function showModal(name, model) {
if (controller.onShow) { controller.onShow(); }
controller.set('flashMessage', null);
}
return controller;
}
};

View File

@ -1,14 +1,13 @@
export default Em.Mixin.create({
actions: {
didTransition: function() {
var self = this;
Em.run.schedule("afterRender", function() {
self.controllerFor("application").set("showFooter", true);
didTransition() {
Em.run.schedule("afterRender", () => {
this.controllerFor("application").set("showFooter", true);
});
return true;
},
willTransition: function() {
willTransition() {
this.controllerFor("application").set("showFooter", false);
return true;
}

View File

@ -8,7 +8,10 @@ export default RestrictedUserRoute.extend(ShowFooter, {
},
setupController(controller, user) {
controller.setProperties({ model: user, newNameInput: user.get('name') });
controller.setProperties({
model: user,
newNameInput: user.get('name')
});
},
actions: {
@ -16,15 +19,15 @@ export default RestrictedUserRoute.extend(ShowFooter, {
showModal('avatar-selector');
// all the properties needed for displaying the avatar selector modal
const controller = this.controllerFor('avatar-selector');
const user = this.modelFor('user');
const props = user.getProperties(
'username', 'email',
'uploaded_avatar_id',
'system_avatar_upload_id',
'gravatar_avatar_upload_id',
'custom_avatar_upload_id'
);
const controller = this.controllerFor('avatar-selector'),
props = this.modelFor('user').getProperties(
'email',
'username',
'uploaded_avatar_id',
'system_avatar_upload_id',
'gravatar_avatar_upload_id',
'custom_avatar_upload_id'
);
switch (props.uploaded_avatar_id) {
case props.system_avatar_upload_id:
@ -40,20 +43,20 @@ export default RestrictedUserRoute.extend(ShowFooter, {
controller.setProperties(props);
},
saveAvatarSelection: function() {
const user = this.modelFor('user');
const avatarSelector = this.controllerFor('avatar-selector');
saveAvatarSelection() {
const user = this.modelFor('user'),
avatarSelector = this.controllerFor('avatar-selector');
// 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(function(){
user.setProperties(avatarSelector.getProperties(
'system_avatar_upload_id',
'gravatar_avatar_upload_id',
'custom_avatar_upload_id'
));
});
.then(() => {
user.setProperties(avatarSelector.getProperties(
'system_avatar_upload_id',
'gravatar_avatar_upload_id',
'custom_avatar_upload_id'
));
});
}
// saves the data back

View File

@ -2,9 +2,8 @@
export default Discourse.Route.extend({
afterModel: function() {
var user = this.modelFor('user');
if (!user.get('can_edit')) {
afterModel() {
if (!this.modelFor('user').get('can_edit')) {
this.replaceWith('userActivity');
}
}

View File

@ -7,14 +7,14 @@
<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>
<button href {{action "refreshGravatar"}} title="{{i18n 'user.change_avatar.refresh_gravatar_title'}}" {{bind-attr enabled="view.gravatarRefreshEnabled"}} class="btn no-text"><i class="fa fa-refresh"></i></button>
{{d-button action="refreshGravatar" title="user.change_avatar.refresh_gravatar_title" disabled=gravatarRefreshDisabled class="no-text" icon="refresh"}}
</div>
<div>
<input type="radio" id="uploaded_avatar" name="avatar" value="uploaded" {{action "useUploadedAvatar"}}>
<label class="radio" for="uploaded_avatar">
{{#if view.hasUploadedAvatar}}
{{#if view.uploadedAvatarTemplate}}
{{bound-avatar-template view.uploadedAvatarTemplate "large"}}
{{#if hasUploadedAvatar}}
{{#if uploadedAvatarTemplate}}
{{bound-avatar-template uploadedAvatarTemplate "large"}}
{{else}}
{{bound-avatar controller "large" custom_avatar_upload_id}} {{i18n 'user.change_avatar.uploaded_avatar'}}
{{/if}}
@ -23,14 +23,14 @@
{{/if}}
</label>
{{avatar-uploader username=username
uploadedAvatarTemplate=view.uploadedAvatarTemplate
custom_avatar_upload_id=controller.custom_avatar_upload_id
uploadedAvatarTemplate=uploadedAvatarTemplate
custom_avatar_upload_id=custom_avatar_upload_id
done="useUploadedAvatar"}}
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" {{action "saveAvatarSelection"}} {{bind-attr disabled="view.saveDisabled"}}>{{i18n 'save'}}</button>
{{d-button action="saveAvatarSelection" class="btn-primary" disabled=saveDisabled label="save"}}
<a {{action "closeModal"}}>{{i18n 'cancel'}}</a>
</div>

View File

@ -54,7 +54,7 @@
<div class="controls">
<span class='static'>{{email}}</span>
{{#if can_edit_email}}
{{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}<i class="fa fa-pencil"></i>{{/link-to}}
{{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}{{fa-icon "pencil"}}{{/link-to}}
{{/if}}
</div>
<div class='instructions'>
@ -62,7 +62,7 @@
</div>
{{else}}
<div class="controls">
<button class="btn" title="{{i18n 'admin.users.check_email.title'}}" {{action "checkEmail" this}}>{{fa-icon "envelope-o"}} {{i18n 'admin.users.check_email.text'}}</button>
{{d-button action="checkEmail" actionParam=this title="admin.users.check_email.title" icon="envelope-o" label="admin.users.check_email.text"}}
</div>
{{/if}}
</div>
@ -72,7 +72,8 @@
<div class="control-group pref-password">
<label class="control-label">{{i18n 'user.password.title'}}</label>
<div class="controls">
<a href="#" {{action "changePassword"}} class='btn'><i class="fa fa-envelope"></i>
<a href="#" {{action "changePassword"}} class='btn'>
{{fa-icon "envelope"}}
{{#if no_password}}
{{i18n 'user.change_password.set_password'}}
{{else}}
@ -87,9 +88,10 @@
<div class="control-group pref-avatar">
<label class="control-label">{{i18n 'user.avatar.title'}}</label>
<div class="controls">
{{bound-avatar model "large"}}
{{! we want the "huge" version even though we're downsizing it to "large" in CSS }}
{{bound-avatar model "huge"}}
{{#if allowAvatarUpload}}
<button {{action "showAvatarSelector"}} class="btn pad-left no-text">{{fa-icon "pencil"}}</button>
{{d-button action="showAvatarSelector" class="pad-left no-text" icon="pencil"}}
{{else}}
{{#unless ssoOverridesAvatar}}
<a href="//gravatar.com/emails" target="_blank" title="{{i18n 'user.change_avatar.gravatar_title'}}" class="btn no-text">{{fa-icon "pencil"}}</a>
@ -245,7 +247,7 @@
<div class="control-group delete-account">
<hr/>
<div class="controls">
<button {{action "delete"}} {{bind-attr disabled="deleteDisabled"}} class="btn btn-danger"><i class="fa fa-trash-o"></i> {{i18n 'user.delete_account'}}</button>
{{d-button action="delete" disabled="deleteDisabled" class="btn-danger" icon="trash-o" label="user.delete_account"}}
</div>
</div>
{{/if}}

View File

@ -4,9 +4,6 @@ export default ModalBodyView.extend({
templateName: 'modal/avatar_selector',
classNames: ['avatar-selector'],
title: I18n.t('user.change_avatar.title'),
saveDisabled: false,
gravatarRefreshEnabled: Em.computed.not('controller.gravatarRefreshDisabled'),
hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'controller.custom_avatar_upload_id'),
// *HACK* used to select the proper radio button, cause {{action}}
// stops the default behavior

View File

@ -170,6 +170,13 @@
border-bottom: 1px solid scale-color-diff();
}
}
.pref-avatar {
.avatar {
max-width: 45px;
max-height: 45px;
}
}
}
.about {

View File

@ -3,7 +3,8 @@ moduleFor("controller:avatar-selector", "controller:avatar-selector", {
});
test("avatarTemplate", function() {
var avatarSelectorController = this.subject();
const avatarSelectorController = this.subject();
avatarSelectorController.setProperties({
selected: "system",
system_avatar_upload_id:1,
@ -11,17 +12,11 @@ test("avatarTemplate", function() {
custom_avatar_upload_id: 3
});
equal(avatarSelectorController.get("selectedUploadId"), 1,
"we are using system by default");
equal(avatarSelectorController.get("selectedUploadId"), 1, "we are using system by default");
avatarSelectorController.set('selected', 'gravatar');
equal(avatarSelectorController.get("selectedUploadId"), 2,
"we are using gravatar when set");
equal(avatarSelectorController.get("selectedUploadId"), 2, "we are using gravatar when set");
avatarSelectorController.set("selected", "custom");
equal(avatarSelectorController.get("selectedUploadId"), 3,
"we are using custom when set");
equal(avatarSelectorController.get("selectedUploadId"), 3, "we are using custom when set");
});