Merge branch 'master' into master
This commit is contained in:
commit
7e93434b1c
|
|
@ -46,8 +46,10 @@ func TestRedirectsNoLogin(t *testing.T) {
|
|||
prepareTestEnv(t)
|
||||
|
||||
var redirects = map[string]string{
|
||||
"/user2/repo1/commits/master": "/user2/repo1/commits/branch/master",
|
||||
"/user2/repo1/src/master": "/user2/repo1/src/branch/master",
|
||||
"/user2/repo1/commits/master": "/user2/repo1/commits/branch/master",
|
||||
"/user2/repo1/src/master": "/user2/repo1/src/branch/master",
|
||||
"/user2/repo1/src/master/file.txt": "/user2/repo1/src/branch/master/file.txt",
|
||||
"/user2/repo1/src/master/directory/file.txt": "/user2/repo1/src/branch/master/directory/file.txt",
|
||||
}
|
||||
for link, redirectLink := range redirects {
|
||||
req := NewRequest(t, "GET", link)
|
||||
|
|
|
|||
|
|
@ -19,3 +19,25 @@
|
|||
issue_id: 2
|
||||
created_unix: 946684800
|
||||
updated_unix: 946684800
|
||||
|
||||
-
|
||||
id: 3
|
||||
user_id: 2
|
||||
repo_id: 1
|
||||
status: 3 # pinned
|
||||
source: 1 # issue
|
||||
updated_by: 1
|
||||
issue_id: 2
|
||||
created_unix: 946684800
|
||||
updated_unix: 946684800
|
||||
|
||||
-
|
||||
id: 4
|
||||
user_id: 2
|
||||
repo_id: 1
|
||||
status: 1 # unread
|
||||
source: 1 # issue
|
||||
updated_by: 1
|
||||
issue_id: 2
|
||||
created_unix: 946684800
|
||||
updated_unix: 946684800
|
||||
|
|
@ -311,3 +311,13 @@ func getNotificationByID(notificationID int64) (*Notification, error) {
|
|||
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
// UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus
|
||||
func UpdateNotificationStatuses(user *User, currentStatus NotificationStatus, desiredStatus NotificationStatus) error {
|
||||
n := &Notification{Status: desiredStatus, UpdatedBy: user.ID}
|
||||
_, err := x.
|
||||
Where("user_id = ? AND status = ?", user.ID, currentStatus).
|
||||
Cols("status", "updated_by", "updated_unix").
|
||||
Update(n)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ func TestNotificationsForUser(t *testing.T) {
|
|||
statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
|
||||
notfs, err := NotificationsForUser(user, statuses, 1, 10)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, notfs, 1) {
|
||||
if assert.Len(t, notfs, 2) {
|
||||
assert.EqualValues(t, 2, notfs[0].ID)
|
||||
assert.EqualValues(t, user.ID, notfs[0].UserID)
|
||||
assert.EqualValues(t, 4, notfs[1].ID)
|
||||
assert.EqualValues(t, user.ID, notfs[1].UserID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,12 +59,12 @@ func TestNotification_GetIssue(t *testing.T) {
|
|||
|
||||
func TestGetNotificationCount(t *testing.T) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
||||
cnt, err := GetNotificationCount(user, NotificationStatusUnread)
|
||||
user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
|
||||
cnt, err := GetNotificationCount(user, NotificationStatusRead)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, cnt)
|
||||
|
||||
cnt, err = GetNotificationCount(user, NotificationStatusRead)
|
||||
cnt, err = GetNotificationCount(user, NotificationStatusUnread)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, cnt)
|
||||
}
|
||||
|
|
@ -79,3 +81,21 @@ func TestSetNotificationStatus(t *testing.T) {
|
|||
assert.Error(t, SetNotificationStatus(1, user, NotificationStatusRead))
|
||||
assert.Error(t, SetNotificationStatus(NonexistentID, user, NotificationStatusRead))
|
||||
}
|
||||
|
||||
func TestUpdateNotificationStatuses(t *testing.T) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
|
||||
notfUnread := AssertExistsAndLoadBean(t,
|
||||
&Notification{UserID: user.ID, Status: NotificationStatusUnread}).(*Notification)
|
||||
notfRead := AssertExistsAndLoadBean(t,
|
||||
&Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification)
|
||||
notfPinned := AssertExistsAndLoadBean(t,
|
||||
&Notification{UserID: user.ID, Status: NotificationStatusPinned}).(*Notification)
|
||||
assert.NoError(t, UpdateNotificationStatuses(user, NotificationStatusUnread, NotificationStatusRead))
|
||||
AssertExistsAndLoadBean(t,
|
||||
&Notification{ID: notfUnread.ID, Status: NotificationStatusRead})
|
||||
AssertExistsAndLoadBean(t,
|
||||
&Notification{ID: notfRead.ID, Status: NotificationStatusRead})
|
||||
AssertExistsAndLoadBean(t,
|
||||
&Notification{ID: notfPinned.ID, Status: NotificationStatusPinned})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,10 +100,6 @@ func populateRepoIndexer() error {
|
|||
}
|
||||
}
|
||||
|
||||
type updateBatch struct {
|
||||
updates []indexer.RepoIndexerUpdate
|
||||
}
|
||||
|
||||
func updateRepoIndexer(repo *Repository) error {
|
||||
changes, err := getRepoChanges(repo)
|
||||
if err != nil {
|
||||
|
|
@ -163,6 +159,10 @@ func addUpdate(filename string, repo *Repository, batch *indexer.Batch) error {
|
|||
return err
|
||||
} else if stat.Size() > setting.Indexer.MaxIndexerFileSize {
|
||||
return nil
|
||||
} else if stat.IsDir() {
|
||||
// file could actually be a directory, if it is the root of a submodule.
|
||||
// We do not index submodule contents, so don't do anything.
|
||||
return nil
|
||||
}
|
||||
fileContents, err := ioutil.ReadFile(filepath)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -626,7 +626,11 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
|
|||
|
||||
if refType == RepoRefLegacy {
|
||||
// redirect from old URL scheme to new URL scheme
|
||||
ctx.Redirect(path.Join(setting.AppSubURL, strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")), ctx.Repo.BranchNameSubURL()))
|
||||
ctx.Redirect(path.Join(
|
||||
setting.AppSubURL,
|
||||
strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")),
|
||||
ctx.Repo.BranchNameSubURL(),
|
||||
ctx.Repo.TreePath))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1569,6 +1569,7 @@ no_read = You do not have any read notifications.
|
|||
pin = Pin notification
|
||||
mark_as_read = Mark as read
|
||||
mark_as_unread = Mark as unread
|
||||
mark_all_as_read = Mark all as read
|
||||
|
||||
[gpg]
|
||||
error.extract_sign = Failed to extract signature
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -152,11 +152,13 @@ pre, code {
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* overide semantic selector '.ui.menu:not(.vertical) .item > .button' */
|
||||
.menu:not(.vertical) .item .button {
|
||||
padding-bottom: .78571429em;
|
||||
padding-top: .78571429em;
|
||||
font-size: 1em;
|
||||
/* Overide semantic selector '.ui.menu:not(.vertical) .item > .button' */
|
||||
/* This fixes the commit graph button on the commits page */
|
||||
.menu:not(.vertical) .item > .button.compact {
|
||||
padding: .58928571em 1.125em;
|
||||
}
|
||||
.menu:not(.vertical) .item > .button.small {
|
||||
font-size: .92857143rem;
|
||||
}
|
||||
|
||||
.text {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -76,11 +77,7 @@ func TeamsAction(ctx *context.Context) {
|
|||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
uname := ctx.Query("uname")
|
||||
// uname may be formatted as "username (fullname)"
|
||||
if strings.Contains(uname, "(") && strings.HasSuffix(uname, ")") {
|
||||
uname = strings.TrimSpace(strings.Split(uname, "(")[0])
|
||||
}
|
||||
uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("uname")))
|
||||
var u *models.User
|
||||
u, err = models.GetUserByName(uname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -367,7 +368,7 @@ func Collaboration(ctx *context.Context) {
|
|||
|
||||
// CollaborationPost response for actions for a collaboration of a repository
|
||||
func CollaborationPost(ctx *context.Context) {
|
||||
name := strings.ToLower(ctx.Query("collaborator"))
|
||||
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("collaborator")))
|
||||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
||||
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -710,6 +710,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Group("/notifications", func() {
|
||||
m.Get("", user.Notifications)
|
||||
m.Post("/status", user.NotificationStatusPost)
|
||||
m.Post("/purge", user.NotificationPurgePost)
|
||||
}, reqSignIn)
|
||||
|
||||
m.Group("/api", func() {
|
||||
|
|
|
|||
|
|
@ -112,3 +112,15 @@ func NotificationStatusPost(c *context.Context) {
|
|||
url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
|
||||
c.Redirect(url, 303)
|
||||
}
|
||||
|
||||
// NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read
|
||||
func NotificationPurgePost(c *context.Context) {
|
||||
err := models.UpdateNotificationStatuses(c.User, models.NotificationStatusUnread, models.NotificationStatusRead)
|
||||
if err != nil {
|
||||
c.Handle(500, "ErrUpdateNotificationStatuses", err)
|
||||
return
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
|
||||
c.Redirect(url, 303)
|
||||
}
|
||||
|
|
|
|||
17
routers/utils/utils.go
Normal file
17
routers/utils/utils.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2017 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 utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RemoveUsernameParameterSuffix returns the username parameter without the (fullname) suffix - leaving just the username
|
||||
func RemoveUsernameParameterSuffix(name string) string {
|
||||
if index := strings.Index(name, " ("); index >= 0 {
|
||||
name = name[:index]
|
||||
}
|
||||
return name
|
||||
}
|
||||
17
routers/utils/utils_test.go
Normal file
17
routers/utils/utils_test.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2017 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 utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRemoveUsernameParameterSuffix(t *testing.T) {
|
||||
assert.Equal(t, "foobar", RemoveUsernameParameterSuffix("foobar (Foo Bar)"))
|
||||
assert.Equal(t, "foobar", RemoveUsernameParameterSuffix("foobar"))
|
||||
assert.Equal(t, "", RemoveUsernameParameterSuffix(""))
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<div class="ui secondary menu">
|
||||
{{template "repo/branch_dropdown" .}}
|
||||
<div class="fitted item">
|
||||
<a href="{{.RepoLink}}/graph" class="ui basic small button">
|
||||
<a href="{{.RepoLink}}/graph" class="ui basic small compact button">
|
||||
<span class="text">
|
||||
<i class="octicon octicon-git-branch"></i>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@
|
|||
<a href="{{AppSubUrl}}/notifications?q=read" class="{{if eq .Status 2}}active{{end}} item">
|
||||
{{.i18n.Tr "notification.read"}}
|
||||
</a>
|
||||
{{if and (eq .Status 1) (.NotificationUnreadCount)}}
|
||||
<form action="{{AppSubUrl}}/notifications/purge" method="POST" style="margin-left: auto;">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<button class="ui mini button primary" title='{{$.i18n.Tr "notification.mark_all_as_read"}}'>
|
||||
<i class="octicon octicon-checklist"></i>
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="ui bottom attached active tab segment">
|
||||
{{if eq (len .Notifications) 0}}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user