diff --git a/app/assets/javascripts/discourse/lib/avatar-template.js.es6 b/app/assets/javascripts/discourse/lib/avatar-template.js.es6 index 542e9795961..15948aba2a6 100644 --- a/app/assets/javascripts/discourse/lib/avatar-template.js.es6 +++ b/app/assets/javascripts/discourse/lib/avatar-template.js.es6 @@ -4,6 +4,7 @@ let _splitAvatars; function defaultAvatar(username) { const defaultAvatars = Discourse.SiteSettings.default_avatars; + if (defaultAvatars && defaultAvatars.length) { _splitAvatars = _splitAvatars || defaultAvatars.split("\n"); @@ -13,20 +14,13 @@ function defaultAvatar(username) { } } - return Discourse.getURLWithCDN("/letter_avatar/" + - username.toLowerCase() + - "/{size}/" + - Discourse.LetterAvatarVersion + ".png"); + const extension = Discourse.SiteSettings.svg_letter_avatars ? "svg" : "png"; + return Discourse.getURLWithCDN(`/letter_avatar/${username.toLowerCase()}/{size}/${Discourse.LetterAvatarVersion}.${extension}`); } export default function(username, uploadedAvatarId) { if (uploadedAvatarId) { - return Discourse.getURLWithCDN("/user_avatar/" + - Discourse.BaseUrl + - "/" + - username.toLowerCase() + - "/{size}/" + - uploadedAvatarId + ".png"); + return Discourse.getURLWithCDN(`/user_avatar/${Discourse.BaseUrl}/${username.toLowerCase()}/{size}/${uploadedAvatarId}.png`); } return defaultAvatar(username); } diff --git a/app/controllers/user_avatars_controller.rb b/app/controllers/user_avatars_controller.rb index ed8f31e4af0..f1d6e7d1db5 100644 --- a/app/controllers/user_avatars_controller.rb +++ b/app/controllers/user_avatars_controller.rb @@ -3,7 +3,7 @@ require_dependency 'letter_avatar' class UserAvatarsController < ApplicationController DOT = Base64.decode64("R0lGODlhAQABALMAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwICAgP8AAAD/AP//AAAA//8A/wD//wBiZCH5BAEAAA8ALAAAAAABAAEAAAQC8EUAOw==") - skip_before_filter :preload_json, :redirect_to_login_if_required, :check_xhr, :verify_authenticity_token, only: [:show, :show_letter] + skip_before_filter :preload_json, :redirect_to_login_if_required, :check_xhr, :verify_authenticity_token, only: [:show, :show_letter, :show_letter_svg] def refresh_gravatar user = User.find_by(username_lower: params[:username].downcase) @@ -19,6 +19,30 @@ class UserAvatarsController < ApplicationController end end + def show_letter_svg + params.require(:username) + params.require(:version) + params.require(:size) + + no_cookies + + size = params[:size].to_i + username = params[:username] + + identity = LetterAvatar::Identity.from_username(username) + color = identity.color + + svg = <<-SVG + + + #{username[0].capitalize} + + SVG + + expires_in 1.year, public: true + render inline: svg, content_type: "image/svg+xml" + end + def show_letter params.require(:username) params.require(:version) diff --git a/app/models/user.rb b/app/models/user.rb index 2861fff881a..cd23445641f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -457,7 +457,7 @@ class User < ActiveRecord::Base avatar_template = split_avatars[hash.abs % split_avatars.size] end else - "#{Discourse.base_uri}/letter_avatar/#{username.downcase}/{size}/#{LetterAvatar.version}.png" + letter_avatar_template(username) end end @@ -469,7 +469,8 @@ class User < ActiveRecord::Base end def self.letter_avatar_template(username) - "#{Discourse.base_uri}/letter_avatar/#{username.downcase}/{size}/#{LetterAvatar.version}.png" + extension = SiteSetting.svg_letter_avatars ? "svg" : "png" + "#{Discourse.base_uri}/letter_avatar/#{username.downcase}/{size}/#{LetterAvatar.version}.#{extension}" end def avatar_template diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fcd190dc8e4..921edd59ed4 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -979,6 +979,8 @@ en: avatar_sizes: "List of automatically generated avatar sizes." + svg_letter_avatars: "Use SVG for letter avatars" + enable_flash_video_onebox: "Enable embedding of swf and flv (Adobe Flash) links in oneboxes. WARNING: may introduce security risks." default_invitee_trust_level: "Default trust level (0-4) for invited users." diff --git a/config/routes.rb b/config/routes.rb index 66125570f49..f5b5aa1b3db 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -299,6 +299,7 @@ Discourse::Application.routes.draw do get "user-badges/:username" => "user_badges#username", constraints: {username: USERNAME_ROUTE_FORMAT} post "user_avatar/:username/refresh_gravatar" => "user_avatars#refresh_gravatar", constraints: {username: USERNAME_ROUTE_FORMAT} + get "letter_avatar/:username/:size/:version.svg" => "user_avatars#show_letter_svg", format: :svg, constraints: { hostname: /[\w\.-]+/, size: /\d+/, username: USERNAME_ROUTE_FORMAT} get "letter_avatar/:username/:size/:version.png" => "user_avatars#show_letter", format: false, constraints: { hostname: /[\w\.-]+/, size: /\d+/, username: USERNAME_ROUTE_FORMAT} get "user_avatar/:hostname/:username/:size/:version.png" => "user_avatars#show", format: false, constraints: { hostname: /[\w\.-]+/, size: /\d+/, username: USERNAME_ROUTE_FORMAT } diff --git a/config/site_settings.yml b/config/site_settings.yml index 754e067b827..0c4950ad843 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -572,6 +572,9 @@ files: avatar_sizes: default: '20|25|32|45|60|120' type: list + svg_letter_avatars: + default: false + client: true trust: default_trust_level: diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 22f9ffe1e89..e82106b96d1 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -30,7 +30,6 @@ module Email # images @fragment.css('img').each do |img| - next if img['class'] == 'site-logo' if img['class'] == "emoji" || img['src'] =~ /plugins\/emoji/ @@ -58,7 +57,6 @@ module Email # attachments @fragment.css('a.attachment').each do |a| - # ensure all urls are absolute if a['href'] =~ /^\/[^\/]/ a['href'] = "#{Discourse.base_url}#{a['href']}" diff --git a/lib/letter_avatar.rb b/lib/letter_avatar.rb index abde76ec080..e49ab6c417a 100644 --- a/lib/letter_avatar.rb +++ b/lib/letter_avatar.rb @@ -7,20 +7,20 @@ class LetterAvatar FULLSIZE = 120 * 3 POINTSIZE = 280 - class << self + class Identity + attr_accessor :color, :letter - class Identity - attr_accessor :color, :letter - - def self.from_username(username) - identity = new - identity.color = LetterAvatar::COLORS[ - Digest::MD5.hexdigest(username)[0...15].to_i(16) % LetterAvatar::COLORS.length - ] - identity.letter = username[0].upcase - identity - end + def self.from_username(username) + identity = new + identity.color = LetterAvatar::COLORS[ + Digest::MD5.hexdigest(username)[0...15].to_i(16) % LetterAvatar::COLORS.length + ] + identity.letter = username[0].upcase + identity end + end + + class << self def version "#{VERSION}_#{image_magick_version}" @@ -32,7 +32,7 @@ class LetterAvatar def generate(username, size, opts = nil) DistributedMutex.synchronize("letter_avatar_#{version}_#{username}") do - identity = Identity.from_username(username) + identity = LetterAvatar::Identity.from_username(username) cache = true cache = false if opts && opts[:cache] == false