diff --git a/app/scripts/src/app.jsx b/app/scripts/src/app.jsx index 35751f8..a79d9af 100644 --- a/app/scripts/src/app.jsx +++ b/app/scripts/src/app.jsx @@ -15,8 +15,9 @@ var Storage = { var App = React.createClass({ mixins: [Router.Navigation, Router.State], - orgsURL: "/api/orgs", - teamsURL: "/api/teams?org=", + orgsURL: '/api/orgs', + teamsURL: '/api/teams?org=', + usersURL: '/api/users?org=', getInitialState: function() { return { @@ -30,6 +31,7 @@ var App = React.createClass({ componentDidMount: function() { this.loadOrgs(); this.loadTeams(); + this.loadUsers(); }, loadOrgs: function() { @@ -46,7 +48,7 @@ var App = React.createClass({ loadTeams: function() { $.get(this.teamsURL + this.getParams().org, function(res){ - this.setState({teams: res}) + this.setState({teams: res}); if (res !== null) { for (var i = 0; i < res.length; i++) { var team = res[i]; @@ -56,6 +58,18 @@ var App = React.createClass({ }.bind(this)); }, + loadUsers: function() { + $.get(this.usersURL + this.getParams().org, function(res){ + this.setState({users: res}); + if (res !== null) { + for (var i = 0; i < res.length; i++) { + var user = res[i]; + Storage.set('user', user.login, user); + } + } + }.bind(this)); + }, + render: function(){ return (
@@ -133,7 +147,9 @@ var Dashboard = React.createClass({ sacApi = '/api/stat/teams/activity'; sacItems = ['user', 'repo']; } else if (p.user) { - infoTitle = p.user; + var info = Storage.get('user', p.user); + infoImage = info ? info.avatar_url : null; + infoTitle = info && info.name ? info.name : p.user; bcApi = '/api/stat/users/top'; bcItems = ['repo'], sacApi = '/api/stat/users/activity'; diff --git a/db/user.go b/db/user.go index cfcc277..462cef6 100644 --- a/db/user.go +++ b/db/user.go @@ -9,6 +9,16 @@ type User struct { AvatarURL string `json:"avatar_url" db:"avatar_url"` } +const orgUsersQuery = ` +select + u.* +from members m +join teams t on + m.team_id = t.id +join users u on + m.user = u.login +where m.org = ?` + const saveUserQuery = ` insert into users (login, name, id, avatar_url) values (:login, :name, :id, :avatar_url) @@ -19,3 +29,9 @@ func (u *User) Save() { defer measure("SaveUser", time.Now()) mustExecN(saveUserQuery, u) } + +func OrgUsers(login string) (users []*User) { + defer measure("OrgUsers", time.Now()) + mustSelect(&users, orgUsersQuery, login) + return +} diff --git a/server/api.go b/server/api.go index 5ace053..64b021b 100644 --- a/server/api.go +++ b/server/api.go @@ -18,6 +18,12 @@ func apiTeamsHandler(w http.ResponseWriter, r *http.Request) { req.respondWith(teams) } +func apiUsersHandler(w http.ResponseWriter, r *http.Request) { + req, stat := parseRequest(w, r) + users := db.OrgUsers(stat.Org) + req.respondWith(users) +} + func apiReposHandler(w http.ResponseWriter, r *http.Request) { req, stat := parseRequest(w, r) repos := db.OrgRepos(stat.Org) diff --git a/server/server.go b/server/server.go index e33b7cd..1b5db7f 100644 --- a/server/server.go +++ b/server/server.go @@ -22,6 +22,7 @@ func init() { http.HandleFunc("/api/", authHandler) http.HandleFunc("/api/orgs", apiOrgsHandler) http.HandleFunc("/api/teams", apiTeamsHandler) + http.HandleFunc("/api/users", apiUsersHandler) http.HandleFunc("/api/repos", apiReposHandler) http.HandleFunc("/api/stat/orgs/top", statOrgTopHandler)