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))) | ||||
| 	} | ||||
|  | ||||
| 	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}) | ||||
|  | ||||
| 	if opts.OnlyPerformedBy { | ||||
|   | ||||
| @@ -214,6 +214,8 @@ var migrations = []Migration{ | ||||
| 	NewMigration("prepend refs/heads/ to issue refs", prependRefsHeadsToIssueRefs), | ||||
| 	// v140 -> v141 | ||||
| 	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 | ||||
|   | ||||
							
								
								
									
										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"` | ||||
|  | ||||
| 	// Preferences | ||||
| 	DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | ||||
| 	Theme         string `xorm:"NOT NULL DEFAULT ''"` | ||||
| 	DiffViewStyle       string `xorm:"NOT NULL DEFAULT ''"` | ||||
| 	Theme               string `xorm:"NOT NULL DEFAULT ''"` | ||||
| 	KeepActivityPrivate bool   `xorm:"NOT NULL DEFAULT false"` | ||||
| } | ||||
|  | ||||
| // SearchOrganizationsOptions options to filter organizations | ||||
|   | ||||
| @@ -18,6 +18,11 @@ type UserHeatmapData struct { | ||||
| // GetUserHeatmapDataByUser returns an array of UserHeatmapData | ||||
| func GetUserHeatmapDataByUser(user *User) ([]*UserHeatmapData, error) { | ||||
| 	hdata := make([]*UserHeatmapData, 0) | ||||
|  | ||||
| 	if user.KeepActivityPrivate { | ||||
| 		return hdata, nil | ||||
| 	} | ||||
|  | ||||
| 	var groupBy string | ||||
| 	var groupByName = "timestamp" // We need this extra case because mssql doesn't allow grouping by alias | ||||
| 	switch { | ||||
|   | ||||
| @@ -196,14 +196,15 @@ func (f *AccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) bi | ||||
|  | ||||
| // UpdateProfileForm form for updating profile | ||||
| type UpdateProfileForm struct { | ||||
| 	Name             string `binding:"AlphaDashDot;MaxSize(40)"` | ||||
| 	FullName         string `binding:"MaxSize(100)"` | ||||
| 	Email            string `binding:"Required;Email;MaxSize(254)"` | ||||
| 	KeepEmailPrivate bool | ||||
| 	Website          string `binding:"ValidUrl;MaxSize(255)"` | ||||
| 	Location         string `binding:"MaxSize(50)"` | ||||
| 	Language         string `binding:"Size(5)"` | ||||
| 	Description      string `binding:"MaxSize(255)"` | ||||
| 	Name                string `binding:"AlphaDashDot;MaxSize(40)"` | ||||
| 	FullName            string `binding:"MaxSize(100)"` | ||||
| 	Email               string `binding:"Required;Email;MaxSize(254)"` | ||||
| 	KeepEmailPrivate    bool | ||||
| 	Website             string `binding:"ValidUrl;MaxSize(255)"` | ||||
| 	Location            string `binding:"MaxSize(50)"` | ||||
| 	Language            string `binding:"Size(5)"` | ||||
| 	Description         string `binding:"MaxSize(255)"` | ||||
| 	KeepActivityPrivate bool | ||||
| } | ||||
|  | ||||
| // Validate validates the fields | ||||
|   | ||||
| @@ -392,6 +392,7 @@ follow = Follow | ||||
| unfollow = Unfollow | ||||
| heatmap.loading = Loading Heatmap… | ||||
| 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_pattern_not_allowed = The pattern '%s' is not allowed in a username. | ||||
| @@ -430,6 +431,9 @@ continue = Continue | ||||
| cancel = Cancel | ||||
| language = Language | ||||
| 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 | ||||
| federated_avatar_lookup = Federated Avatar Lookup | ||||
|   | ||||
| @@ -112,7 +112,9 @@ func Dashboard(ctx *context.Context) { | ||||
| 	ctx.Data["PageIsDashboard"] = true | ||||
| 	ctx.Data["PageIsNews"] = true | ||||
| 	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 | ||||
|  | ||||
| 	var err error | ||||
|   | ||||
| @@ -93,7 +93,9 @@ func Profile(ctx *context.Context) { | ||||
| 	ctx.Data["PageIsUserProfile"] = true | ||||
| 	ctx.Data["Owner"] = ctxUser | ||||
| 	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 | ||||
| 	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.Language = form.Language | ||||
| 	ctx.User.Description = form.Description | ||||
| 	ctx.User.KeepActivityPrivate = form.KeepActivityPrivate | ||||
| 	if err := models.UpdateUserSetting(ctx.User); err != nil { | ||||
| 		if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | ||||
| 			ctx.Flash.Error(ctx.Tr("form.email_been_used")) | ||||
|   | ||||
| @@ -104,10 +104,15 @@ | ||||
| 				</div> | ||||
|  | ||||
| 				{{if eq .TabName "activity"}} | ||||
| 				{{if .EnableHeatmap}} | ||||
| 					{{template "user/dashboard/heatmap" .}} | ||||
| 					<div class="ui divider"></div> | ||||
| 				{{end}} | ||||
| 					{{if .Owner.KeepActivityPrivate}} | ||||
| 						<div class="ui info message"> | ||||
| 							<p>{{.i18n.Tr "user.disabled_public_activity"}}</p> | ||||
| 						</div> | ||||
| 					{{end}} | ||||
| 					{{if .EnableHeatmap}} | ||||
| 						{{template "user/dashboard/heatmap" .}} | ||||
| 						<div class="ui divider"></div> | ||||
| 					{{end}} | ||||
| 					<div class="feeds"> | ||||
| 						{{template "user/dashboard/feeds" .}} | ||||
| 					</div> | ||||
|   | ||||
| @@ -58,6 +58,13 @@ | ||||
| 						</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"> | ||||
| 					<button class="ui green button">{{$.i18n.Tr "settings.update_profile"}}</button> | ||||
| 				</div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user