Improved logo upload. Also show logo at login page.
This commit is contained in:
parent
4f74a73017
commit
8636466f87
12 changed files with 204 additions and 64 deletions
|
@ -216,9 +216,13 @@ class Base extends App.ControllerContent
|
||||||
else
|
else
|
||||||
url = "#{http_type}://#{fqdn}"
|
url = "#{http_type}://#{fqdn}"
|
||||||
|
|
||||||
|
logoFile = App.Config.get('product_logo')
|
||||||
|
logoUrl = App.Config.get('image_path') + "/#{logoFile}"
|
||||||
|
|
||||||
organization = App.Config.get('organization')
|
organization = App.Config.get('organization')
|
||||||
@html App.view('getting_started/base')(
|
@html App.view('getting_started/base')(
|
||||||
url: url
|
url: url
|
||||||
|
logoUrl: logoUrl
|
||||||
organization: organization
|
organization: organization
|
||||||
)
|
)
|
||||||
@$("input, select").first().focus()
|
@$("input, select").first().focus()
|
||||||
|
@ -237,7 +241,7 @@ class Base extends App.ControllerContent
|
||||||
if !file
|
if !file
|
||||||
return
|
return
|
||||||
|
|
||||||
maxSiteInMb = 3
|
maxSiteInMb = 8
|
||||||
if file.size && file.size > 1024 * 1024 * maxSiteInMb
|
if file.size && file.size > 1024 * 1024 * maxSiteInMb
|
||||||
@showAlert( 'logo', App.i18n.translateInline( 'File too big, max. %s MB allowed.', maxSiteInMb ) )
|
@showAlert( 'logo', App.i18n.translateInline( 'File too big, max. %s MB allowed.', maxSiteInMb ) )
|
||||||
@logoPreview.attr( 'src', '' )
|
@logoPreview.attr( 'src', '' )
|
||||||
|
@ -250,8 +254,15 @@ class Base extends App.ControllerContent
|
||||||
|
|
||||||
# get params
|
# get params
|
||||||
params = @formParam(e.target)
|
params = @formParam(e.target)
|
||||||
|
|
||||||
|
# add logo
|
||||||
params['logo'] = @logoPreview.attr('src')
|
params['logo'] = @logoPreview.attr('src')
|
||||||
|
|
||||||
|
# add resized image
|
||||||
|
if params['logo']
|
||||||
|
resizeLogo = new App.ImageService( params['logo'] )
|
||||||
|
params['logo_resize'] = resizeLogo.toDataURLForApp( @logoPreview.width(), @logoPreview.height() )
|
||||||
|
|
||||||
@hideAlerts()
|
@hideAlerts()
|
||||||
@disable(e)
|
@disable(e)
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,15 @@ class Index extends App.ControllerContent
|
||||||
}
|
}
|
||||||
auth_providers = []
|
auth_providers = []
|
||||||
for key, provider of auth_provider_all
|
for key, provider of auth_provider_all
|
||||||
if @Config.get( provider.config ) is true || @Config.get( provider.config ) is "true"
|
if @Config.get( provider.config ) is true || @Config.get( provider.config ) is 'true'
|
||||||
auth_providers.push provider
|
auth_providers.push provider
|
||||||
|
|
||||||
|
logoFile = App.Config.get('product_logo')
|
||||||
|
logoUrl = App.Config.get('image_path') + "/#{logoFile}"
|
||||||
|
|
||||||
@html App.view('login')(
|
@html App.view('login')(
|
||||||
item: data
|
item: data
|
||||||
|
logoUrl: logoUrl
|
||||||
auth_providers: auth_providers
|
auth_providers: auth_providers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
class App.ImageService
|
||||||
|
constructor: (url) ->
|
||||||
|
@orgDataURL = url
|
||||||
|
|
||||||
|
src: (url) =>
|
||||||
|
@orgDataURL = url
|
||||||
|
|
||||||
|
resize: ( x = 'auto', y = 'auto') =>
|
||||||
|
@canvas = document.createElement('canvas')
|
||||||
|
context = @canvas.getContext('2d')
|
||||||
|
|
||||||
|
# load image from data url
|
||||||
|
imageObject = new Image()
|
||||||
|
imageObject.src = @orgDataURL
|
||||||
|
imageWidth = imageObject.width
|
||||||
|
imageHeight = imageObject.height
|
||||||
|
|
||||||
|
if y is 'auto' && x is 'auto'
|
||||||
|
x = imageWidth
|
||||||
|
y = imageHeight
|
||||||
|
|
||||||
|
# get auto dimensions
|
||||||
|
if y is 'auto'
|
||||||
|
factor = imageWidth / x
|
||||||
|
y = imageHeight / factor
|
||||||
|
|
||||||
|
if x is 'auto'
|
||||||
|
factor = imageWidth / y
|
||||||
|
x = imageHeight / factor
|
||||||
|
|
||||||
|
console.log('BB', x, y)
|
||||||
|
# set canvas dimensions
|
||||||
|
@canvas.width = x
|
||||||
|
@canvas.height = y
|
||||||
|
|
||||||
|
# draw image on canvas and set image dimensions
|
||||||
|
context.drawImage( imageObject, 0, 0, x, y )
|
||||||
|
@canvas
|
||||||
|
|
||||||
|
toDataURL: (type, quallity = 1) =>
|
||||||
|
#@resize()
|
||||||
|
@canvas.toDataURL( type, quallity )
|
||||||
|
|
||||||
|
toDataURLForApp: ( x, y ) =>
|
||||||
|
@resize( x * 2, y * 2 )
|
||||||
|
@toDataURL( 'image/jpeg', 0.7 )
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><%- @T('Logo') %></label>
|
<label><%- @T('Logo') %></label>
|
||||||
<div class="alert alert--danger hide" role="alert"></div>
|
<div class="alert alert--danger hide" role="alert"></div>
|
||||||
<img class="logo-preview" src="">
|
<img class="logo-preview" src="<%= @logoUrl %>">
|
||||||
<div class="logo-preview-placeholder"><%- @T('Your Logo') %></div>
|
<div class="logo-preview-placeholder"><%- @T('Your Logo') %></div>
|
||||||
<div class="btn btn--success fileUpload"><%- @T('Upload') %><input type="file" class="js-upload" name="logo" accept="image/*"></div>
|
<div class="btn btn--success fileUpload"><%- @T('Upload') %><input type="file" class="js-upload" name="logo" accept="image/*"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<p><%- @T( 'Login with %s', @C( 'fqdn' ) ) %></p>
|
<p><%- @T( 'Login with %s', @C( 'fqdn' ) ) %></p>
|
||||||
|
|
||||||
<div class="hero-unit">
|
<div class="hero-unit">
|
||||||
<img class="company-logo" src="<%= @C('api_path') + '/sessions/logo' %>" alt="<%= @C( 'product_name' ) %>">
|
<img class="company-logo" src="<%= @logoUrl %>" alt="<%= @C( 'product_name' ) %>">
|
||||||
<form id="login">
|
<form id="login">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username"><%- @Ti( 'Username / email' ) %></label>
|
<label for="username"><%- @Ti( 'Username / email' ) %></label>
|
||||||
|
|
|
@ -106,27 +106,28 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
|
||||||
|
|
||||||
# save image
|
# save image
|
||||||
if params[:logo] && !params[:logo].empty?
|
if params[:logo] && !params[:logo].empty?
|
||||||
content_type = nil
|
|
||||||
content = nil
|
|
||||||
|
|
||||||
# data:image/png;base64
|
# data:image/png;base64
|
||||||
if params[:logo] =~ /^data:(.+?);base64,(.+?)$/
|
file = StaticAssets.data_url_attributes( params[:logo] )
|
||||||
content_type = $1
|
|
||||||
content = Base64.decode64($2)
|
# store image 1:1
|
||||||
end
|
StaticAssets.store_raw( file[:content], file[:content_type] )
|
||||||
Store.remove( :object => 'System::Logo', :o_id => 1 )
|
|
||||||
Store.add(
|
|
||||||
:object => 'System::Logo',
|
|
||||||
:o_id => 1,
|
|
||||||
:data => content,
|
|
||||||
:filename => 'image',
|
|
||||||
:preferences => {
|
|
||||||
'Content-Type' => content_type
|
|
||||||
},
|
|
||||||
# :created_by_id => self.updated_by_id,
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if params[:logo_resize] && !params[:logo_resize].empty?
|
||||||
|
|
||||||
|
# data:image/png;base64
|
||||||
|
file = StaticAssets.data_url_attributes( params[:logo_resize] )
|
||||||
|
|
||||||
|
# store image 1:1
|
||||||
|
settings[:product_logo] = StaticAssets.store( file[:content], file[:content_type] )
|
||||||
|
end
|
||||||
|
|
||||||
|
# set changed settings
|
||||||
|
settings.each {|key, value|
|
||||||
|
Setting.set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
render :json => {
|
render :json => {
|
||||||
:result => 'ok',
|
:result => 'ok',
|
||||||
:settings => settings,
|
:settings => settings,
|
||||||
|
|
|
@ -279,45 +279,4 @@ class SessionsController < ApplicationController
|
||||||
render :json => {}
|
render :json => {}
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
Resource:
|
|
||||||
GET /api/v1/sessions/logo
|
|
||||||
|
|
||||||
Response:
|
|
||||||
<IMAGE>
|
|
||||||
|
|
||||||
Test:
|
|
||||||
curl http://localhost/api/v1/sessions/logo
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def logo
|
|
||||||
|
|
||||||
# cache image
|
|
||||||
#response.headers['Expires'] = 1.year.from_now.httpdate
|
|
||||||
#response.headers["Cache-Control"] = "cache, store, max-age=31536000, must-revalidate"
|
|
||||||
#response.headers["Pragma"] = "cache"
|
|
||||||
|
|
||||||
# find logo
|
|
||||||
list = Store.list( :object => 'System::Logo', :o_id => 2 )
|
|
||||||
if list && list[0]
|
|
||||||
file = Store.find( list[0] )
|
|
||||||
send_data(
|
|
||||||
file.content,
|
|
||||||
:filename => file.filename,
|
|
||||||
:type => file.preferences['Content-Type'],
|
|
||||||
:disposition => 'inline'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
# serve default image
|
|
||||||
send_data(
|
|
||||||
'',
|
|
||||||
:filename => '',
|
|
||||||
:type => 'image/gif',
|
|
||||||
:disposition => 'inline'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
2
config/initializers/logo.rb
Normal file
2
config/initializers/logo.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# sync logo to fs
|
||||||
|
StaticAssets.sync
|
|
@ -15,7 +15,6 @@ Zammad::Application.routes.draw do
|
||||||
match api_path + '/sessions/switch/:id', :to => 'sessions#switch_to_user', :via => :get
|
match api_path + '/sessions/switch/:id', :to => 'sessions#switch_to_user', :via => :get
|
||||||
match api_path + '/sessions/switch_back', :to => 'sessions#switch_back_to_user', :via => :get
|
match api_path + '/sessions/switch_back', :to => 'sessions#switch_back_to_user', :via => :get
|
||||||
match api_path + '/sessions', :to => 'sessions#list', :via => :get
|
match api_path + '/sessions', :to => 'sessions#list', :via => :get
|
||||||
match api_path + '/sessions/logo', :to => 'sessions#logo', :via => :get
|
|
||||||
match api_path + '/sessions/:id', :to => 'sessions#delete', :via => :delete
|
match api_path + '/sessions/:id', :to => 'sessions#delete', :via => :delete
|
||||||
|
|
||||||
end
|
end
|
25
db/migrate/20141119000001_update_setting2.rb
Normal file
25
db/migrate/20141119000001_update_setting2.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
class UpdateSetting2 < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
:title => 'Logo',
|
||||||
|
:name => 'product_logo',
|
||||||
|
:area => 'System::CI',
|
||||||
|
:description => 'Defines the logo of the application, shown in the web interface.',
|
||||||
|
:options => {
|
||||||
|
:form => [
|
||||||
|
{
|
||||||
|
:display => '',
|
||||||
|
:null => false,
|
||||||
|
:name => 'product_logo',
|
||||||
|
:tag => 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
:state => 'logo.svg',
|
||||||
|
:frontend => true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
18
db/seeds.rb
18
db/seeds.rb
|
@ -33,6 +33,24 @@ Setting.create_if_not_exists(
|
||||||
:state => 'Zammad',
|
:state => 'Zammad',
|
||||||
:frontend => true
|
:frontend => true
|
||||||
)
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
:title => 'Logo',
|
||||||
|
:name => 'product_logo',
|
||||||
|
:area => 'System::CI',
|
||||||
|
:description => 'Defines the logo of the application, shown in the web interface.',
|
||||||
|
:options => {
|
||||||
|
:form => [
|
||||||
|
{
|
||||||
|
:display => '',
|
||||||
|
:null => false,
|
||||||
|
:name => 'product_logo',
|
||||||
|
:tag => 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
:state => 'logo.svg',
|
||||||
|
:frontend => true
|
||||||
|
)
|
||||||
|
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
:title => 'Organization',
|
:title => 'Organization',
|
||||||
|
|
75
lib/static_assets.rb
Normal file
75
lib/static_assets.rb
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
module StaticAssets
|
||||||
|
|
||||||
|
def self.data_url_attributes( data_url )
|
||||||
|
data = {}
|
||||||
|
if data_url =~ /^data:(.+?);base64,(.+?)$/
|
||||||
|
data[:content_type] = $1
|
||||||
|
data[:content] = Base64.decode64($2)
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
raise "Unable to parse data url: #{data_url.substr(0,100)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# store image 1:1
|
||||||
|
def self.store_raw( content, content_type )
|
||||||
|
Store.remove( :object => 'System::Logo', :o_id => 1 )
|
||||||
|
Store.add(
|
||||||
|
:object => 'System::Logo',
|
||||||
|
:o_id => 1,
|
||||||
|
:data => content,
|
||||||
|
:filename => 'image',
|
||||||
|
:preferences => {
|
||||||
|
'Content-Type' => content_type
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Digest::MD5.hexdigest( content )
|
||||||
|
end
|
||||||
|
|
||||||
|
# read raw 1:1
|
||||||
|
def self.read_raw
|
||||||
|
list = Store.list( :object => 'System::Logo', :o_id => 1 )
|
||||||
|
if list && list[0]
|
||||||
|
return Store.find( list[0] )
|
||||||
|
end
|
||||||
|
raise "No such raw logo!"
|
||||||
|
end
|
||||||
|
|
||||||
|
# store image in right size
|
||||||
|
def self.store( content, content_type )
|
||||||
|
Store.remove( :object => 'System::Logo', :o_id => 2 )
|
||||||
|
Store.add(
|
||||||
|
:object => 'System::Logo',
|
||||||
|
:o_id => 2,
|
||||||
|
:data => content,
|
||||||
|
:filename => 'image',
|
||||||
|
:preferences => {
|
||||||
|
'Content-Type' => content_type
|
||||||
|
},
|
||||||
|
)
|
||||||
|
StaticAssets.sync
|
||||||
|
Digest::MD5.hexdigest( content )
|
||||||
|
end
|
||||||
|
|
||||||
|
# read image
|
||||||
|
def self.read
|
||||||
|
list = Store.list( :object => 'System::Logo', :o_id => 2 )
|
||||||
|
if list && list[0]
|
||||||
|
file = Store.find( list[0] )
|
||||||
|
hash = Digest::MD5.hexdigest( file.content )
|
||||||
|
Setting.set('product_logo', hash)
|
||||||
|
return file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# sync image to fs
|
||||||
|
def self.sync
|
||||||
|
file = read
|
||||||
|
return if !file
|
||||||
|
|
||||||
|
hash = Digest::MD5.hexdigest( file.content )
|
||||||
|
path = "#{Rails.root.to_s}/public/assets/#{hash}"
|
||||||
|
File.open( path, 'wb' ) do |f|
|
||||||
|
f.puts file.content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue