Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User action heatmap #5131

Merged
merged 34 commits into from Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
26bb85f
Added basic heatmap data
kolaente Oct 20, 2018
f27fe68
Added extra case for sqlite
kolaente Oct 20, 2018
af87a62
Built basic heatmap into user profile
kolaente Oct 20, 2018
562257c
Get contribution data from api & styling
kolaente Oct 20, 2018
1a36952
Fixed lint & added extra group by statements for all database types
kolaente Oct 20, 2018
1ae7ed2
generated swagger spec
kolaente Oct 20, 2018
7823d45
generated swagger spec
kolaente Oct 20, 2018
3f2562a
generated swagger spec
kolaente Oct 20, 2018
a1d3fb7
fixed swagger spec
kolaente Oct 20, 2018
5d99fc5
fmt
kolaente Oct 20, 2018
63cf602
Added tests
kolaente Oct 20, 2018
b01dcd2
Added setting to enable/disable user heatmap
kolaente Oct 20, 2018
cac8299
Added locale for loading text
kolaente Oct 20, 2018
a831999
Removed UseTiDB
kolaente Oct 20, 2018
068eaaf
Merge branch 'master' into feature/commit-heatmap
kolaente Oct 20, 2018
fdd3132
Updated librejs & moment.js
kolaente Oct 20, 2018
dd04de8
Merge remote-tracking branch 'origin/feature/commit-heatmap' into fea…
kolaente Oct 20, 2018
86aa012
Merge branch 'master' into feature/commit-heatmap
kolaente Oct 20, 2018
8fb9857
Merge branch 'master' into feature/commit-heatmap
kolaente Oct 20, 2018
3a85ca7
Fixed import order
kolaente Oct 20, 2018
bed8f3c
Merge remote-tracking branch 'origin/feature/commit-heatmap' into fea…
kolaente Oct 20, 2018
6e9519f
Fixed heatmap in postgresql
kolaente Oct 21, 2018
6d724e6
Update docs/content/doc/advanced/config-cheat-sheet.en-us.md
sapk Oct 21, 2018
7ecaeac
Merge branch 'master' into feature/commit-heatmap
kolaente Oct 21, 2018
9db3069
Added copyright header
kolaente Oct 21, 2018
2ea5a1e
Fixed a bug to show the heatmap for the actual user instead of the cu…
kolaente Oct 21, 2018
06846be
Added integration test for heatmaps
kolaente Oct 21, 2018
20a35d6
Added a heatmap on the dashboard
kolaente Oct 21, 2018
81d98ed
Fixed timestamp parsing
kolaente Oct 21, 2018
e441242
Merge branch 'master' into feature/commit-heatmap
kolaente Oct 21, 2018
8de8db1
Hide heatmap on mobile
kolaente Oct 21, 2018
9c0e184
optimized postgresql group by query
kolaente Oct 21, 2018
727171a
Improved sqlite group by statement
kolaente Oct 22, 2018
e8a7559
Merge branch 'master' into feature/commit-heatmap
lunny Oct 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Expand Up @@ -193,6 +193,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default.
- `ENABLE_USER_HEATMAP`: **true** Enable this to display the heatmap on users profiles.

## Webhook (`webhook`)

Expand Down
30 changes: 30 additions & 0 deletions integrations/api_user_heatmap_test.go
@@ -0,0 +1,30 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.package models

package integrations

import (
"code.gitea.io/gitea/models"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)

func TestUserHeatmap(t *testing.T) {
prepareTestEnv(t)
adminUsername := "user1"
normalUsername := "user2"
session := loginUser(t, adminUsername)

urlStr := fmt.Sprintf("/api/v1/users/%s/heatmap", normalUsername)
req := NewRequest(t, "GET", urlStr)
resp := session.MakeRequest(t, req, http.StatusOK)
var heatmap []*models.UserHeatmapData
DecodeJSON(t, resp, &heatmap)
var dummyheatmap []*models.UserHeatmapData
dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1540080000, Contributions: 1})

assert.Equal(t, dummyheatmap, heatmap)
}
1 change: 1 addition & 0 deletions models/fixtures/action.yml
Expand Up @@ -5,6 +5,7 @@
act_user_id: 2
repo_id: 2
is_private: true
created_unix: 1540139562

-
id: 2
Expand Down
1 change: 1 addition & 0 deletions models/unit_tests.go
Expand Up @@ -48,6 +48,7 @@ func MainTest(m *testing.M, pathToGiteaRoot string) {
setting.RunUser = "runuser"
setting.SSH.Port = 3000
setting.SSH.Domain = "try.gitea.io"
setting.UseSQLite3 = true
lafriks marked this conversation as resolved.
Show resolved Hide resolved
setting.RepoRootPath, err = ioutil.TempDir(os.TempDir(), "repos")
if err != nil {
fatalTestError("TempDir: %v\n", err)
Expand Down
40 changes: 40 additions & 0 deletions models/user_heatmap.go
@@ -0,0 +1,40 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.package models

package models
kolaente marked this conversation as resolved.
Show resolved Hide resolved

import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)

// UserHeatmapData represents the data needed to create a heatmap
type UserHeatmapData struct {
Timestamp util.TimeStamp `json:"timestamp"`
Contributions int64 `json:"contributions"`
}

// GetUserHeatmapDataByUser returns an array of UserHeatmapData
func GetUserHeatmapDataByUser(user *User) (hdata []*UserHeatmapData, err error) {
var groupBy string
switch {
case setting.UseSQLite3:
groupBy = "CAST(strftime('%Y-%m-%d', created_unix, 'unixepoch') AS INT)"
kolaente marked this conversation as resolved.
Show resolved Hide resolved
kolaente marked this conversation as resolved.
Show resolved Hide resolved
case setting.UseMySQL:
groupBy = "UNIX_TIMESTAMP(DATE_FORMAT(FROM_UNIXTIME(created_unix), '%Y%m%d'))"
case setting.UsePostgreSQL:
groupBy = "extract(epoch from date_trunc('day', to_timestamp(created_unix)))"
case setting.UseMSSQL:
groupBy = "dateadd(DAY,0, datediff(day,0, dateadd(s, created_unix, '19700101')))"
}

err = x.Select(groupBy+" as timestamp, count(user_id) as contributions").
Table("action").
Where("user_id = ?", user.ID).
And("created_unix > ?", (util.TimeStampNow() - 31536000)).
GroupBy("timestamp").
OrderBy("timestamp").
Find(&hdata)
return
}
33 changes: 33 additions & 0 deletions models/user_heatmap_test.go
@@ -0,0 +1,33 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.package models

package models
kolaente marked this conversation as resolved.
Show resolved Hide resolved

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestGetUserHeatmapDataByUser(t *testing.T) {
// Prepare
assert.NoError(t, PrepareTestDatabase())

// Insert some action
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)

// get the action for comparison
actions, err := GetFeeds(GetFeedsOptions{
RequestedUser: user,
RequestingUserID: user.ID,
IncludePrivate: true,
OnlyPerformedBy: false,
IncludeDeleted: true,
})
assert.NoError(t, err)

// Get the heatmap and compare
heatmap, err := GetUserHeatmapDataByUser(user)
assert.NoError(t, err)
assert.Equal(t, len(actions), len(heatmap))
}
2 changes: 2 additions & 0 deletions modules/setting/setting.go
Expand Up @@ -1218,6 +1218,7 @@ var Service struct {
DefaultEnableDependencies bool
DefaultAllowOnlyContributorsToTrackTime bool
NoReplyAddress string
EnableUserHeatmap bool

// OpenID settings
EnableOpenIDSignIn bool
Expand Down Expand Up @@ -1249,6 +1250,7 @@ func newService() {
Service.DefaultEnableDependencies = sec.Key("DEFAULT_ENABLE_DEPENDENCIES").MustBool(true)
Service.DefaultAllowOnlyContributorsToTrackTime = sec.Key("DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME").MustBool(true)
Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org")
Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true)

sec = Cfg.Section("openid")
Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Expand Up @@ -320,6 +320,7 @@ starred = Starred Repositories
following = Following
follow = Follow
unfollow = Unfollow
heatmap.loading = Loading Heatmap…

form.name_reserved = The username '%s' is reserved.
form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username.
Expand Down
2 changes: 1 addition & 1 deletion public/css/index.css

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions public/less/_base.less
Expand Up @@ -588,3 +588,20 @@ footer {
border-bottom-width: 0 !important;
margin-bottom: 2px !important;
}

#user-heatmap{
width: 107%; // Fixes newest contributions not showing
text-align: center;
margin: 40px 0 30px;

svg:not(:root) {
overflow: inherit;
padding: 0 !important;
}

@media only screen and (max-width: 1200px) {
& {
display: none;
}
}
}
4 changes: 4 additions & 0 deletions public/less/_user.less
Expand Up @@ -58,6 +58,10 @@
.ui.repository.list {
margin-top: 25px;
}

kolaente marked this conversation as resolved.
Show resolved Hide resolved
#loading-heatmap{
margin-bottom: 1em;
}
}

&.followers {
Expand Down
9 changes: 9 additions & 0 deletions public/vendor/VERSIONS
Expand Up @@ -58,3 +58,12 @@ Version: 4.3.0

File(s): /vendor/assets/swagger-ui/
Version: 3.0.4

kolaente marked this conversation as resolved.
Show resolved Hide resolved
File(s): /vendor/plugins/d3/
Version: 4.13.0

File(s): /vendor/plugins/calendar-heatmap/
Version: 337b431

File(s): /vendor/plugins/moment/
Version: 2.22.2
15 changes: 15 additions & 0 deletions public/vendor/librejs.html
Expand Up @@ -135,6 +135,21 @@
<td><a href="https://github.com/swagger-api/swagger-ui/blob/master/LICENSE">Apache-2.0</a></td>
<td><a href="https://github.com/swagger-api/swagger-ui/archive/v3.0.4.tar.gz">swagger-ui-v3.0.4.tar.gz</a></td>
</tr>
<tr>
<td><a href="./plugins/d3/">d3</a></td>
<td><a href="https://github.com/d3/d3/blob/master/LICENSE">BSD 3-Clause</a></td>
<td><a href="https://github.com/d3/d3/releases/download/v4.13.0/d3.zip">d3.zip</a></td>
</tr>
<tr>
<td><a href="./plugins/calendar-heatmap/">calendar-heatmap</a></td>
<td><a href="https://github.com/DKirwan/calendar-heatmap/blob/master/LICENSE">MIT</a></td>
<td><a href="https://github.com/DKirwan/calendar-heatmap/archive/master.zip">337b431.zip</a></td>
</tr>
<tr>
<td><a href="./plugins/moment/">moment.js</a></td>
<td><a href="https://github.com/moment/moment/blob/develop/LICENSE">MIT</a></td>
<td><a href="https://github.com/moment/moment/archive/2.22.2.tar.gz">0.4.1.tar.gz</a></td>
</tr>
</tbody>
</table>
</body>
Expand Down
27 changes: 27 additions & 0 deletions public/vendor/plugins/calendar-heatmap/calendar-heatmap.css
@@ -0,0 +1,27 @@
text.month-name,
text.calendar-heatmap-legend-text,
text.day-initial {
font-size: 10px;
fill: inherit;
font-family: Helvetica, arial, 'Open Sans', sans-serif;
}
rect.day-cell:hover {
stroke: #555555;
stroke-width: 1px;
}
.day-cell-tooltip {
position: absolute;
z-index: 9999;
padding: 5px 9px;
color: #bbbbbb;
font-size: 12px;
background: rgba(0, 0, 0, 0.85);
border-radius: 3px;
text-align: center;
}
.day-cell-tooltip > span {
font-family: Helvetica, arial, 'Open Sans', sans-serif
}
.calendar-heatmap {
box-sizing: initial;
}