Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
aaf6dd2c
Commit
aaf6dd2c
authored
Feb 21, 2016
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'avatar'
parents
13720759
08f7ccff
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
264 additions
and
3 deletions
+264
-3
pkg/api/api.go
+5
-0
pkg/api/avatar/avatar.go
+253
-0
pkg/api/dtos/models.go
+2
-1
pkg/api/index.go
+1
-1
public/app/core/components/sidemenu/sidemenu.html
+1
-1
public/img/transparent.png
+0
-0
public/sass/components/_sidemenu.scss
+2
-0
No files found.
pkg/api/api.go
View file @
aaf6dd2c
...
...
@@ -2,6 +2,7 @@ package api
import
(
"github.com/go-macaron/binding"
"github.com/grafana/grafana/pkg/api/avatar"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/middleware"
m
"github.com/grafana/grafana/pkg/models"
...
...
@@ -224,6 +225,10 @@ func Register(r *macaron.Macaron) {
// rendering
r
.
Get
(
"/render/*"
,
reqSignedIn
,
RenderToPng
)
// Gravatar service.
avt
:=
avatar
.
CacheServer
()
r
.
Get
(
"/avatar/:hash"
,
avt
.
ServeHTTP
)
InitAppPluginRoutes
(
r
)
r
.
NotFound
(
NotFoundHandler
)
...
...
pkg/api/avatar/avatar.go
0 → 100644
View file @
aaf6dd2c
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Code from https://github.com/gogits/gogs/blob/v0.7.0/modules/avatar/avatar.go
package
avatar
import
(
"bufio"
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/setting"
)
var
gravatarSource
string
func
UpdateGravatarSource
()
{
srcCfg
:=
"//secure.gravatar.com/avatar/"
gravatarSource
=
srcCfg
if
strings
.
HasPrefix
(
gravatarSource
,
"//"
)
{
gravatarSource
=
"http:"
+
gravatarSource
}
else
if
!
strings
.
HasPrefix
(
gravatarSource
,
"http://"
)
&&
!
strings
.
HasPrefix
(
gravatarSource
,
"https://"
)
{
gravatarSource
=
"http://"
+
gravatarSource
}
}
// hash email to md5 string
// keep this func in order to make this package independent
func
HashEmail
(
email
string
)
string
{
// https://en.gravatar.com/site/implement/hash/
email
=
strings
.
TrimSpace
(
email
)
email
=
strings
.
ToLower
(
email
)
h
:=
md5
.
New
()
h
.
Write
([]
byte
(
email
))
return
hex
.
EncodeToString
(
h
.
Sum
(
nil
))
}
// Avatar represents the avatar object.
type
Avatar
struct
{
hash
string
reqParams
string
data
*
bytes
.
Buffer
notFound
bool
timestamp
time
.
Time
}
func
New
(
hash
string
)
*
Avatar
{
return
&
Avatar
{
hash
:
hash
,
reqParams
:
url
.
Values
{
"d"
:
{
"404"
},
"size"
:
{
"200"
},
"r"
:
{
"pg"
}}
.
Encode
(),
}
}
func
(
this
*
Avatar
)
Expired
()
bool
{
return
time
.
Since
(
this
.
timestamp
)
>
(
time
.
Minute
*
10
)
}
func
(
this
*
Avatar
)
Encode
(
wr
io
.
Writer
)
error
{
_
,
err
:=
wr
.
Write
(
this
.
data
.
Bytes
())
return
err
}
func
(
this
*
Avatar
)
Update
()
(
err
error
)
{
select
{
case
<-
time
.
After
(
time
.
Second
*
3
)
:
err
=
fmt
.
Errorf
(
"get gravatar image %s timeout"
,
this
.
hash
)
case
err
=
<-
thunder
.
GoFetch
(
gravatarSource
+
this
.
hash
+
"?"
+
this
.
reqParams
,
this
)
:
}
return
err
}
type
service
struct
{
notFound
*
Avatar
cache
map
[
string
]
*
Avatar
}
func
(
this
*
service
)
mustInt
(
r
*
http
.
Request
,
defaultValue
int
,
keys
...
string
)
(
v
int
)
{
for
_
,
k
:=
range
keys
{
if
_
,
err
:=
fmt
.
Sscanf
(
r
.
FormValue
(
k
),
"%d"
,
&
v
);
err
==
nil
{
defaultValue
=
v
}
}
return
defaultValue
}
func
(
this
*
service
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
urlPath
:=
r
.
URL
.
Path
hash
:=
urlPath
[
strings
.
LastIndex
(
urlPath
,
"/"
)
+
1
:
]
var
avatar
*
Avatar
if
avatar
,
_
=
this
.
cache
[
hash
];
avatar
==
nil
{
avatar
=
New
(
hash
)
}
if
avatar
.
Expired
()
{
if
err
:=
avatar
.
Update
();
err
!=
nil
{
log
.
Trace
(
"avatar update error: %v"
,
err
)
}
}
if
avatar
.
notFound
{
avatar
=
this
.
notFound
}
else
{
this
.
cache
[
hash
]
=
avatar
}
w
.
Header
()
.
Set
(
"Content-Type"
,
"image/jpeg"
)
w
.
Header
()
.
Set
(
"Content-Length"
,
strconv
.
Itoa
(
len
(
avatar
.
data
.
Bytes
())))
w
.
Header
()
.
Set
(
"Cache-Control"
,
"private, max-age=3600"
)
if
err
:=
avatar
.
Encode
(
w
);
err
!=
nil
{
log
.
Warn
(
"avatar encode error: %v"
,
err
)
w
.
WriteHeader
(
500
)
}
}
func
CacheServer
()
http
.
Handler
{
UpdateGravatarSource
()
return
&
service
{
notFound
:
newNotFound
(),
cache
:
make
(
map
[
string
]
*
Avatar
),
}
}
func
newNotFound
()
*
Avatar
{
avatar
:=
&
Avatar
{}
// load transparent png into buffer
path
:=
filepath
.
Join
(
setting
.
StaticRootPath
,
"img"
,
"transparent.png"
)
if
data
,
err
:=
ioutil
.
ReadFile
(
path
);
err
!=
nil
{
log
.
Error
(
3
,
"Failed to read transparent.png, %v"
,
path
)
}
else
{
avatar
.
data
=
bytes
.
NewBuffer
(
data
)
}
return
avatar
}
// thunder downloader
var
thunder
=
&
Thunder
{
QueueSize
:
10
}
type
Thunder
struct
{
QueueSize
int
// download queue size
q
chan
*
thunderTask
once
sync
.
Once
}
func
(
t
*
Thunder
)
init
()
{
if
t
.
QueueSize
<
1
{
t
.
QueueSize
=
1
}
t
.
q
=
make
(
chan
*
thunderTask
,
t
.
QueueSize
)
for
i
:=
0
;
i
<
t
.
QueueSize
;
i
++
{
go
func
()
{
for
{
task
:=
<-
t
.
q
task
.
Fetch
()
}
}()
}
}
func
(
t
*
Thunder
)
Fetch
(
url
string
,
avatar
*
Avatar
)
error
{
t
.
once
.
Do
(
t
.
init
)
task
:=
&
thunderTask
{
Url
:
url
,
Avatar
:
avatar
,
}
task
.
Add
(
1
)
t
.
q
<-
task
task
.
Wait
()
return
task
.
err
}
func
(
t
*
Thunder
)
GoFetch
(
url
string
,
avatar
*
Avatar
)
chan
error
{
c
:=
make
(
chan
error
)
go
func
()
{
c
<-
t
.
Fetch
(
url
,
avatar
)
}()
return
c
}
// thunder download
type
thunderTask
struct
{
Url
string
Avatar
*
Avatar
sync
.
WaitGroup
err
error
}
func
(
this
*
thunderTask
)
Fetch
()
{
this
.
err
=
this
.
fetch
()
this
.
Done
()
}
var
client
=
&
http
.
Client
{}
func
(
this
*
thunderTask
)
fetch
()
error
{
this
.
Avatar
.
timestamp
=
time
.
Now
()
log
.
Debug
(
"avatar.fetch(fetch new avatar): %s"
,
this
.
Url
)
req
,
_
:=
http
.
NewRequest
(
"GET"
,
this
.
Url
,
nil
)
req
.
Header
.
Set
(
"Accept"
,
"text/html,application/xhtml+xml,application/xml;q=0.9,image/jpeg,image/png,*/*;q=0.8"
)
req
.
Header
.
Set
(
"Accept-Encoding"
,
"deflate,sdch"
)
req
.
Header
.
Set
(
"Accept-Language"
,
"zh-CN,zh;q=0.8"
)
req
.
Header
.
Set
(
"Cache-Control"
,
"no-cache"
)
req
.
Header
.
Set
(
"User-Agent"
,
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36"
)
resp
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
this
.
Avatar
.
notFound
=
true
return
fmt
.
Errorf
(
"gravatar unreachable, %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
200
{
this
.
Avatar
.
notFound
=
true
return
fmt
.
Errorf
(
"status code: %d"
,
resp
.
StatusCode
)
}
this
.
Avatar
.
data
=
&
bytes
.
Buffer
{}
writer
:=
bufio
.
NewWriter
(
this
.
Avatar
.
data
)
if
_
,
err
=
io
.
Copy
(
writer
,
resp
.
Body
);
err
!=
nil
{
return
err
}
return
nil
}
pkg/api/dtos/models.go
View file @
aaf6dd2c
...
...
@@ -7,6 +7,7 @@ import (
"time"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
type
LoginCommand
struct
{
...
...
@@ -89,5 +90,5 @@ func GetGravatarUrl(text string) string {
hasher
:=
md5
.
New
()
hasher
.
Write
([]
byte
(
strings
.
ToLower
(
text
)))
return
fmt
.
Sprintf
(
"https://secure.gravatar.com/avatar/%x?s=90&default=mm
"
,
hasher
.
Sum
(
nil
))
return
fmt
.
Sprintf
(
setting
.
AppSubUrl
+
"/avatar/%x
"
,
hasher
.
Sum
(
nil
))
}
pkg/api/index.go
View file @
aaf6dd2c
...
...
@@ -36,7 +36,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
}
if
setting
.
DisableGravatar
{
data
.
User
.
GravatarUrl
=
setting
.
AppSubUrl
+
"/public/img/
user_profile
.png"
data
.
User
.
GravatarUrl
=
setting
.
AppSubUrl
+
"/public/img/
transparent
.png"
}
if
len
(
data
.
User
.
Name
)
==
0
{
...
...
public/app/core/components/sidemenu/sidemenu.html
View file @
aaf6dd2c
...
...
@@ -4,7 +4,7 @@
<div
class=
"sidemenu-org"
>
<div
class=
"sidemenu-org-avatar"
>
<img
ng-if=
"ctrl.user.gravatarUrl"
ng-src=
"{{ctrl.user.gravatarUrl}}"
>
<span
class=
"sidemenu-org-avatar--missing"
ng-if=
"!ctrl.user.gravatarUrl"
>
<span
class=
"sidemenu-org-avatar--missing"
>
<i
class=
"fa fa-fw fa-user"
></i>
</span>
</div>
...
...
public/img/transparent.png
0 → 100644
View file @
aaf6dd2c
95 Bytes
public/sass/components/_sidemenu.scss
View file @
aaf6dd2c
...
...
@@ -210,9 +210,11 @@
text-align
:
center
;
>
img
{
position
:
absolute
;
width
:
40px
;
height
:
40px
;
border-radius
:
50%
;
left
:
14px
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment