mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	Add hide activity option (#11353)
* Add hide activity option This closes https://github.com/go-gitea/gitea/issues/7927 * Adjust for linter * Adjust for linter * Add tests * Remove info that admins can view the activity * Adjust new tests for linter * Rename v139.go to v140.go * Rename v140.go to v141.go * properly indent * gofmt Co-authored-by: Jonas Lochmann <git@inkompetenz.org> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
		
							
								
								
									
										414
									
								
								integrations/privateactivity_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								integrations/privateactivity_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | |||||||
|  | // Copyright 2020 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 integrations | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/models" | ||||||
|  | 	api "code.gitea.io/gitea/modules/structs" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const privateActivityTestAdmin = "user1" | ||||||
|  | const privateActivityTestUser = "user2" | ||||||
|  |  | ||||||
|  | // user3 is an organization so it is not usable here | ||||||
|  | const privateActivityTestOtherUser = "user4" | ||||||
|  |  | ||||||
|  | // activity helpers | ||||||
|  |  | ||||||
|  | func testPrivateActivityDoSomethingForActionEntries(t *testing.T) { | ||||||
|  | 	repoBefore := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) | ||||||
|  | 	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repoBefore.OwnerID}).(*models.User) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	token := getTokenForLoggedInUser(t, session) | ||||||
|  | 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repoBefore.Name, token) | ||||||
|  | 	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{ | ||||||
|  | 		Body:  "test", | ||||||
|  | 		Title: "test", | ||||||
|  | 	}) | ||||||
|  | 	session.MakeRequest(t, req, http.StatusCreated) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // private activity helpers | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperEnablePrivateActivity(t *testing.T) { | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ | ||||||
|  | 		"_csrf":                 GetCSRF(t, session, "/user/settings"), | ||||||
|  | 		"name":                  privateActivityTestUser, | ||||||
|  | 		"email":                 privateActivityTestUser + "@example.com", | ||||||
|  | 		"language":              "en-us", | ||||||
|  | 		"keep_activity_private": "1", | ||||||
|  | 	}) | ||||||
|  | 	session.MakeRequest(t, req, http.StatusFound) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleActivitiesInHTMLDoc(htmlDoc *HTMLDoc) bool { | ||||||
|  | 	return htmlDoc.doc.Find(".feeds").Find(".news").Length() > 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleActivitiesFromSession(t *testing.T, session *TestSession) bool { | ||||||
|  | 	req := NewRequestf(t, "GET", "/%s?tab=activity", privateActivityTestUser) | ||||||
|  | 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	htmlDoc := NewHTMLParser(t, resp.Body) | ||||||
|  |  | ||||||
|  | 	return testPrivateActivityHelperHasVisibleActivitiesInHTMLDoc(htmlDoc) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleActivitiesFromPublic(t *testing.T) bool { | ||||||
|  | 	req := NewRequestf(t, "GET", "/%s?tab=activity", privateActivityTestUser) | ||||||
|  | 	resp := MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	htmlDoc := NewHTMLParser(t, resp.Body) | ||||||
|  |  | ||||||
|  | 	return testPrivateActivityHelperHasVisibleActivitiesInHTMLDoc(htmlDoc) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // heatmap UI helpers | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleHeatmapInHTMLDoc(htmlDoc *HTMLDoc) bool { | ||||||
|  | 	return htmlDoc.doc.Find("#user-heatmap").Length() > 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t *testing.T, session *TestSession) bool { | ||||||
|  | 	req := NewRequestf(t, "GET", "/%s?tab=activity", privateActivityTestUser) | ||||||
|  | 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	htmlDoc := NewHTMLParser(t, resp.Body) | ||||||
|  |  | ||||||
|  | 	return testPrivateActivityHelperHasVisibleHeatmapInHTMLDoc(htmlDoc) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleDashboardHeatmapFromSession(t *testing.T, session *TestSession) bool { | ||||||
|  | 	req := NewRequest(t, "GET", "/") | ||||||
|  | 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	htmlDoc := NewHTMLParser(t, resp.Body) | ||||||
|  |  | ||||||
|  | 	return testPrivateActivityHelperHasVisibleHeatmapInHTMLDoc(htmlDoc) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasVisibleHeatmapFromPublic(t *testing.T) bool { | ||||||
|  | 	req := NewRequestf(t, "GET", "/%s?tab=activity", privateActivityTestUser) | ||||||
|  | 	resp := MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	htmlDoc := NewHTMLParser(t, resp.Body) | ||||||
|  |  | ||||||
|  | 	return testPrivateActivityHelperHasVisibleHeatmapInHTMLDoc(htmlDoc) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // heatmap API helpers | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasHeatmapContentFromPublic(t *testing.T) bool { | ||||||
|  | 	req := NewRequestf(t, "GET", "/api/v1/users/%s/heatmap", privateActivityTestUser) | ||||||
|  | 	resp := MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	var items []*models.UserHeatmapData | ||||||
|  | 	DecodeJSON(t, resp, &items) | ||||||
|  |  | ||||||
|  | 	return len(items) != 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testPrivateActivityHelperHasHeatmapContentFromSession(t *testing.T, session *TestSession) bool { | ||||||
|  | 	token := getTokenForLoggedInUser(t, session) | ||||||
|  |  | ||||||
|  | 	req := NewRequestf(t, "GET", "/api/v1/users/%s/heatmap?token=%s", privateActivityTestUser, token) | ||||||
|  | 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||||
|  |  | ||||||
|  | 	var items []*models.UserHeatmapData | ||||||
|  | 	DecodeJSON(t, resp, &items) | ||||||
|  |  | ||||||
|  | 	return len(items) != 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check activity visibility if the visibility is enabled | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoVisibleForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoVisibleForUserItself(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoVisibleForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoVisibleForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check activity visibility if the visibility is disabled | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesInvisibleForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesVisibleForUserItself(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesInvisibleForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesVisibleForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleActivitiesFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible activities") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check heatmap visibility if the visibility is enabled | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapVisibleForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleHeatmapFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapVisibleForUserItselfAtProfile(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapVisibleForUserItselfAtDashboard(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleDashboardHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapVisibleForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapVisibleForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, visible, "user should have visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check heatmap visibility if the visibility is disabled | ||||||
|  | // this behavior, in special the one for the admin, is | ||||||
|  | // due to the fact that the heatmap is the same for all viewers; | ||||||
|  | // otherwise, there is no reason for it | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapInvisibleForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleHeatmapFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapInvisibleForUserItselfAtProfile(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapInvisibleForUserItselfAtDashboard(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleDashboardHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapInvisibleForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapInvsisibleForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	visible := testPrivateActivityHelperHasVisibleProfileHeatmapFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, visible, "user should have no visible heatmap") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check heatmap api provides content if the visibility is enabled | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapHasContentForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.True(t, hasContent, "user should have heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapHasContentForUserItself(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, hasContent, "user should have heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapHasContentForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, hasContent, "user should have heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityNoHeatmapHasContentForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.True(t, hasContent, "user should have heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check heatmap api provides no content if the visibility is disabled | ||||||
|  | // this should be equal to the hidden heatmap at the UI | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapHasNoContentForPublic(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromPublic(t) | ||||||
|  |  | ||||||
|  | 	assert.False(t, hasContent, "user should have no heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapHasNoContentForUserItself(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestUser) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, hasContent, "user should have no heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapHasNoContentForOtherUser(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestOtherUser) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, hasContent, "user should have no heatmap content") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestPrivateActivityYesHeatmapHasNoContentForAdmin(t *testing.T) { | ||||||
|  | 	defer prepareTestEnv(t)() | ||||||
|  | 	testPrivateActivityDoSomethingForActionEntries(t) | ||||||
|  | 	testPrivateActivityHelperEnablePrivateActivity(t) | ||||||
|  |  | ||||||
|  | 	session := loginUser(t, privateActivityTestAdmin) | ||||||
|  | 	hasContent := testPrivateActivityHelperHasHeatmapContentFromSession(t, session) | ||||||
|  |  | ||||||
|  | 	assert.False(t, hasContent, "user should have no heatmap content") | ||||||
|  | } | ||||||
| @@ -319,6 +319,12 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { | |||||||
| 		cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor))) | 		cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor))) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if opts.Actor == nil || !opts.Actor.IsAdmin { | ||||||
|  | 		if opts.RequestedUser.KeepActivityPrivate && actorID != opts.RequestedUser.ID { | ||||||
|  | 			return make([]*Action, 0), nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID}) | 	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID}) | ||||||
|  |  | ||||||
| 	if opts.OnlyPerformedBy { | 	if opts.OnlyPerformedBy { | ||||||
|   | |||||||
| @@ -214,6 +214,8 @@ var migrations = []Migration{ | |||||||
| 	NewMigration("prepend refs/heads/ to issue refs", prependRefsHeadsToIssueRefs), | 	NewMigration("prepend refs/heads/ to issue refs", prependRefsHeadsToIssueRefs), | ||||||
| 	// v140 -> v141 | 	// v140 -> v141 | ||||||
| 	NewMigration("Save detected language file size to database instead of percent", fixLanguageStatsToSaveSize), | 	NewMigration("Save detected language file size to database instead of percent", fixLanguageStatsToSaveSize), | ||||||
|  | 	// v141 -> 142 | ||||||
|  | 	NewMigration("Add KeepActivityPrivate to User table", addKeepActivityPrivateUserColumn), | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetCurrentDBVersion returns the current db version | // GetCurrentDBVersion returns the current db version | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								models/migrations/v141.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								models/migrations/v141.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | // Copyright 2020 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 migrations | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"xorm.io/xorm" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func addKeepActivityPrivateUserColumn(x *xorm.Engine) error { | ||||||
|  | 	type User struct { | ||||||
|  | 		KeepActivityPrivate bool | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := x.Sync2(new(User)); err != nil { | ||||||
|  | 		return fmt.Errorf("Sync2: %v", err) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
| @@ -163,8 +163,9 @@ type User struct { | |||||||
| 	RepoAdminChangeTeamAccess bool                `xorm:"NOT NULL DEFAULT false"` | 	RepoAdminChangeTeamAccess bool                `xorm:"NOT NULL DEFAULT false"` | ||||||
|  |  | ||||||
| 	// Preferences | 	// Preferences | ||||||
| 	DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | 	DiffViewStyle       string `xorm:"NOT NULL DEFAULT ''"` | ||||||
| 	Theme         string `xorm:"NOT NULL DEFAULT ''"` | 	Theme               string `xorm:"NOT NULL DEFAULT ''"` | ||||||
|  | 	KeepActivityPrivate bool   `xorm:"NOT NULL DEFAULT false"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // SearchOrganizationsOptions options to filter organizations | // SearchOrganizationsOptions options to filter organizations | ||||||
|   | |||||||
| @@ -18,6 +18,11 @@ type UserHeatmapData struct { | |||||||
| // GetUserHeatmapDataByUser returns an array of UserHeatmapData | // GetUserHeatmapDataByUser returns an array of UserHeatmapData | ||||||
| func GetUserHeatmapDataByUser(user *User) ([]*UserHeatmapData, error) { | func GetUserHeatmapDataByUser(user *User) ([]*UserHeatmapData, error) { | ||||||
| 	hdata := make([]*UserHeatmapData, 0) | 	hdata := make([]*UserHeatmapData, 0) | ||||||
|  |  | ||||||
|  | 	if user.KeepActivityPrivate { | ||||||
|  | 		return hdata, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var groupBy string | 	var groupBy string | ||||||
| 	var groupByName = "timestamp" // We need this extra case because mssql doesn't allow grouping by alias | 	var groupByName = "timestamp" // We need this extra case because mssql doesn't allow grouping by alias | ||||||
| 	switch { | 	switch { | ||||||
|   | |||||||
| @@ -196,14 +196,15 @@ func (f *AccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) bi | |||||||
|  |  | ||||||
| // UpdateProfileForm form for updating profile | // UpdateProfileForm form for updating profile | ||||||
| type UpdateProfileForm struct { | type UpdateProfileForm struct { | ||||||
| 	Name             string `binding:"AlphaDashDot;MaxSize(40)"` | 	Name                string `binding:"AlphaDashDot;MaxSize(40)"` | ||||||
| 	FullName         string `binding:"MaxSize(100)"` | 	FullName            string `binding:"MaxSize(100)"` | ||||||
| 	Email            string `binding:"Required;Email;MaxSize(254)"` | 	Email               string `binding:"Required;Email;MaxSize(254)"` | ||||||
| 	KeepEmailPrivate bool | 	KeepEmailPrivate    bool | ||||||
| 	Website          string `binding:"ValidUrl;MaxSize(255)"` | 	Website             string `binding:"ValidUrl;MaxSize(255)"` | ||||||
| 	Location         string `binding:"MaxSize(50)"` | 	Location            string `binding:"MaxSize(50)"` | ||||||
| 	Language         string `binding:"Size(5)"` | 	Language            string `binding:"Size(5)"` | ||||||
| 	Description      string `binding:"MaxSize(255)"` | 	Description         string `binding:"MaxSize(255)"` | ||||||
|  | 	KeepActivityPrivate bool | ||||||
| } | } | ||||||
|  |  | ||||||
| // Validate validates the fields | // Validate validates the fields | ||||||
|   | |||||||
| @@ -392,6 +392,7 @@ follow = Follow | |||||||
| unfollow = Unfollow | unfollow = Unfollow | ||||||
| heatmap.loading = Loading Heatmap… | heatmap.loading = Loading Heatmap… | ||||||
| user_bio = Biography | user_bio = Biography | ||||||
|  | disabled_public_activity = This user has disabled the public visibility of the activity. | ||||||
|  |  | ||||||
| form.name_reserved = The username '%s' is reserved. | form.name_reserved = The username '%s' is reserved. | ||||||
| form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username. | form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username. | ||||||
| @@ -430,6 +431,9 @@ continue = Continue | |||||||
| cancel = Cancel | cancel = Cancel | ||||||
| language = Language | language = Language | ||||||
| ui = Theme | ui = Theme | ||||||
|  | privacy = Privacy | ||||||
|  | keep_activity_private = Hide the activity from the profile page | ||||||
|  | keep_activity_private_popup = Makes the activity visible only for you and the admins | ||||||
|  |  | ||||||
| lookup_avatar_by_mail = Look Up Avatar by Email Address | lookup_avatar_by_mail = Look Up Avatar by Email Address | ||||||
| federated_avatar_lookup = Federated Avatar Lookup | federated_avatar_lookup = Federated Avatar Lookup | ||||||
|   | |||||||
| @@ -112,7 +112,9 @@ func Dashboard(ctx *context.Context) { | |||||||
| 	ctx.Data["PageIsDashboard"] = true | 	ctx.Data["PageIsDashboard"] = true | ||||||
| 	ctx.Data["PageIsNews"] = true | 	ctx.Data["PageIsNews"] = true | ||||||
| 	ctx.Data["SearchLimit"] = setting.UI.User.RepoPagingNum | 	ctx.Data["SearchLimit"] = setting.UI.User.RepoPagingNum | ||||||
| 	ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap | 	// no heatmap access for admins; GetUserHeatmapDataByUser ignores the calling user | ||||||
|  | 	// so everyone would get the same empty heatmap | ||||||
|  | 	ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap && !ctxUser.KeepActivityPrivate | ||||||
| 	ctx.Data["HeatmapUser"] = ctxUser.Name | 	ctx.Data["HeatmapUser"] = ctxUser.Name | ||||||
|  |  | ||||||
| 	var err error | 	var err error | ||||||
|   | |||||||
| @@ -93,7 +93,9 @@ func Profile(ctx *context.Context) { | |||||||
| 	ctx.Data["PageIsUserProfile"] = true | 	ctx.Data["PageIsUserProfile"] = true | ||||||
| 	ctx.Data["Owner"] = ctxUser | 	ctx.Data["Owner"] = ctxUser | ||||||
| 	ctx.Data["OpenIDs"] = openIDs | 	ctx.Data["OpenIDs"] = openIDs | ||||||
| 	ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap | 	// no heatmap access for admins; GetUserHeatmapDataByUser ignores the calling user | ||||||
|  | 	// so everyone would get the same empty heatmap | ||||||
|  | 	ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap && !ctxUser.KeepActivityPrivate | ||||||
| 	ctx.Data["HeatmapUser"] = ctxUser.Name | 	ctx.Data["HeatmapUser"] = ctxUser.Name | ||||||
| 	showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID) | 	showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -96,6 +96,7 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { | |||||||
| 	ctx.User.Location = form.Location | 	ctx.User.Location = form.Location | ||||||
| 	ctx.User.Language = form.Language | 	ctx.User.Language = form.Language | ||||||
| 	ctx.User.Description = form.Description | 	ctx.User.Description = form.Description | ||||||
|  | 	ctx.User.KeepActivityPrivate = form.KeepActivityPrivate | ||||||
| 	if err := models.UpdateUserSetting(ctx.User); err != nil { | 	if err := models.UpdateUserSetting(ctx.User); err != nil { | ||||||
| 		if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | 		if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | ||||||
| 			ctx.Flash.Error(ctx.Tr("form.email_been_used")) | 			ctx.Flash.Error(ctx.Tr("form.email_been_used")) | ||||||
|   | |||||||
| @@ -104,10 +104,15 @@ | |||||||
| 				</div> | 				</div> | ||||||
|  |  | ||||||
| 				{{if eq .TabName "activity"}} | 				{{if eq .TabName "activity"}} | ||||||
| 				{{if .EnableHeatmap}} | 					{{if .Owner.KeepActivityPrivate}} | ||||||
| 					{{template "user/dashboard/heatmap" .}} | 						<div class="ui info message"> | ||||||
| 					<div class="ui divider"></div> | 							<p>{{.i18n.Tr "user.disabled_public_activity"}}</p> | ||||||
| 				{{end}} | 						</div> | ||||||
|  | 					{{end}} | ||||||
|  | 					{{if .EnableHeatmap}} | ||||||
|  | 						{{template "user/dashboard/heatmap" .}} | ||||||
|  | 						<div class="ui divider"></div> | ||||||
|  | 					{{end}} | ||||||
| 					<div class="feeds"> | 					<div class="feeds"> | ||||||
| 						{{template "user/dashboard/feeds" .}} | 						{{template "user/dashboard/feeds" .}} | ||||||
| 					</div> | 					</div> | ||||||
|   | |||||||
| @@ -58,6 +58,13 @@ | |||||||
| 						</div> | 						</div> | ||||||
| 					</div> | 					</div> | ||||||
|  |  | ||||||
|  | 				<div class="field"> | ||||||
|  | 					<label for="keep-activity-private">{{.i18n.Tr "settings.privacy"}}</label> | ||||||
|  | 					<div class="ui checkbox" id="keep-activity-private"> | ||||||
|  | 						<label class="poping up" data-content="{{.i18n.Tr "settings.keep_activity_private_popup"}}"><strong>{{.i18n.Tr "settings.keep_activity_private"}}</strong></label> | ||||||
|  | 						<input name="keep_activity_private" type="checkbox" {{if .SignedUser.KeepActivityPrivate}}checked{{end}}> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
| 					<button class="ui green button">{{$.i18n.Tr "settings.update_profile"}}</button> | 					<button class="ui green button">{{$.i18n.Tr "settings.update_profile"}}</button> | ||||||
| 				</div> | 				</div> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user