Skip to content

Commit 80985ee

Browse files
authored
Merge branch 'master' into ssh-passthrough-docker
2 parents 0bc3bac + 4f5ff1e commit 80985ee

File tree

150 files changed

+1039
-1614
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+1039
-1614
lines changed

cmd/doctor.go

Lines changed: 35 additions & 521 deletions
Large diffs are not rendered by default.

models/notification.go

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010

1111
"code.gitea.io/gitea/modules/log"
1212
"code.gitea.io/gitea/modules/setting"
13-
api "code.gitea.io/gitea/modules/structs"
1413
"code.gitea.io/gitea/modules/timeutil"
1514

1615
"xorm.io/builder"
@@ -332,56 +331,6 @@ func countUnread(e Engine, userID int64) int64 {
332331
return exist
333332
}
334333

335-
// APIFormat converts a Notification to api.NotificationThread
336-
func (n *Notification) APIFormat() *api.NotificationThread {
337-
result := &api.NotificationThread{
338-
ID: n.ID,
339-
Unread: !(n.Status == NotificationStatusRead || n.Status == NotificationStatusPinned),
340-
Pinned: n.Status == NotificationStatusPinned,
341-
UpdatedAt: n.UpdatedUnix.AsTime(),
342-
URL: n.APIURL(),
343-
}
344-
345-
//since user only get notifications when he has access to use minimal access mode
346-
if n.Repository != nil {
347-
result.Repository = n.Repository.APIFormat(AccessModeRead)
348-
}
349-
350-
//handle Subject
351-
switch n.Source {
352-
case NotificationSourceIssue:
353-
result.Subject = &api.NotificationSubject{Type: "Issue"}
354-
if n.Issue != nil {
355-
result.Subject.Title = n.Issue.Title
356-
result.Subject.URL = n.Issue.APIURL()
357-
result.Subject.State = n.Issue.State()
358-
comment, err := n.Issue.GetLastComment()
359-
if err == nil && comment != nil {
360-
result.Subject.LatestCommentURL = comment.APIURL()
361-
}
362-
}
363-
case NotificationSourcePullRequest:
364-
result.Subject = &api.NotificationSubject{Type: "Pull"}
365-
if n.Issue != nil {
366-
result.Subject.Title = n.Issue.Title
367-
result.Subject.URL = n.Issue.APIURL()
368-
result.Subject.State = n.Issue.State()
369-
comment, err := n.Issue.GetLastComment()
370-
if err == nil && comment != nil {
371-
result.Subject.LatestCommentURL = comment.APIURL()
372-
}
373-
}
374-
case NotificationSourceCommit:
375-
result.Subject = &api.NotificationSubject{
376-
Type: "Commit",
377-
Title: n.CommitID,
378-
}
379-
//unused until now
380-
}
381-
382-
return result
383-
}
384-
385334
// LoadAttributes load Repo Issue User and Comment if not loaded
386335
func (n *Notification) LoadAttributes() (err error) {
387336
return n.loadAttributes(x)
@@ -470,15 +419,6 @@ func (n *Notification) APIURL() string {
470419
// NotificationList contains a list of notifications
471420
type NotificationList []*Notification
472421

473-
// APIFormat converts a NotificationList to api.NotificationThread list
474-
func (nl NotificationList) APIFormat() []*api.NotificationThread {
475-
var result = make([]*api.NotificationThread, 0, len(nl))
476-
for _, n := range nl {
477-
result = append(result, n.APIFormat())
478-
}
479-
return result
480-
}
481-
482422
// LoadAttributes load Repo Issue User and Comment if not loaded
483423
func (nl NotificationList) LoadAttributes() (err error) {
484424
for i := 0; i < len(nl); i++ {

modules/convert/notification.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package convert
6+
7+
import (
8+
"code.gitea.io/gitea/models"
9+
api "code.gitea.io/gitea/modules/structs"
10+
)
11+
12+
// ToNotificationThread convert a Notification to api.NotificationThread
13+
func ToNotificationThread(n *models.Notification) *api.NotificationThread {
14+
result := &api.NotificationThread{
15+
ID: n.ID,
16+
Unread: !(n.Status == models.NotificationStatusRead || n.Status == models.NotificationStatusPinned),
17+
Pinned: n.Status == models.NotificationStatusPinned,
18+
UpdatedAt: n.UpdatedUnix.AsTime(),
19+
URL: n.APIURL(),
20+
}
21+
22+
//since user only get notifications when he has access to use minimal access mode
23+
if n.Repository != nil {
24+
result.Repository = n.Repository.APIFormat(models.AccessModeRead)
25+
}
26+
27+
//handle Subject
28+
switch n.Source {
29+
case models.NotificationSourceIssue:
30+
result.Subject = &api.NotificationSubject{Type: "Issue"}
31+
if n.Issue != nil {
32+
result.Subject.Title = n.Issue.Title
33+
result.Subject.URL = n.Issue.APIURL()
34+
result.Subject.State = n.Issue.State()
35+
comment, err := n.Issue.GetLastComment()
36+
if err == nil && comment != nil {
37+
result.Subject.LatestCommentURL = comment.APIURL()
38+
}
39+
}
40+
case models.NotificationSourcePullRequest:
41+
result.Subject = &api.NotificationSubject{Type: "Pull"}
42+
if n.Issue != nil {
43+
result.Subject.Title = n.Issue.Title
44+
result.Subject.URL = n.Issue.APIURL()
45+
result.Subject.State = n.Issue.State()
46+
comment, err := n.Issue.GetLastComment()
47+
if err == nil && comment != nil {
48+
result.Subject.LatestCommentURL = comment.APIURL()
49+
}
50+
}
51+
case models.NotificationSourceCommit:
52+
result.Subject = &api.NotificationSubject{
53+
Type: "Commit",
54+
Title: n.CommitID,
55+
}
56+
//unused until now
57+
}
58+
59+
return result
60+
}
61+
62+
// ToNotifications convert list of Notification to api.NotificationThread list
63+
func ToNotifications(nl models.NotificationList) []*api.NotificationThread {
64+
var result = make([]*api.NotificationThread, 0, len(nl))
65+
for _, n := range nl {
66+
result = append(result, ToNotificationThread(n))
67+
}
68+
return result
69+
}

modules/doctor/authorizedkeys.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package doctor
6+
7+
import (
8+
"bufio"
9+
"bytes"
10+
"fmt"
11+
"os"
12+
"path/filepath"
13+
"strings"
14+
15+
"code.gitea.io/gitea/models"
16+
"code.gitea.io/gitea/modules/log"
17+
"code.gitea.io/gitea/modules/setting"
18+
)
19+
20+
const tplCommentPrefix = `# gitea public key`
21+
22+
func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
23+
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
24+
return nil
25+
}
26+
27+
fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
28+
f, err := os.Open(fPath)
29+
if err != nil {
30+
if !autofix {
31+
logger.Critical("Unable to open authorized_keys file. ERROR: %v", err)
32+
return fmt.Errorf("Unable to open authorized_keys file. ERROR: %v", err)
33+
}
34+
logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
35+
if err = models.RewriteAllPublicKeys(); err != nil {
36+
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
37+
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err)
38+
}
39+
}
40+
defer f.Close()
41+
42+
linesInAuthorizedKeys := map[string]bool{}
43+
44+
scanner := bufio.NewScanner(f)
45+
for scanner.Scan() {
46+
line := scanner.Text()
47+
if strings.HasPrefix(line, tplCommentPrefix) {
48+
continue
49+
}
50+
linesInAuthorizedKeys[line] = true
51+
}
52+
f.Close()
53+
54+
// now we regenerate and check if there are any lines missing
55+
regenerated := &bytes.Buffer{}
56+
if err := models.RegeneratePublicKeys(regenerated); err != nil {
57+
logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err)
58+
return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %v", err)
59+
}
60+
scanner = bufio.NewScanner(regenerated)
61+
for scanner.Scan() {
62+
line := scanner.Text()
63+
if strings.HasPrefix(line, tplCommentPrefix) {
64+
continue
65+
}
66+
if ok := linesInAuthorizedKeys[line]; ok {
67+
continue
68+
}
69+
if !autofix {
70+
logger.Critical(
71+
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
72+
fPath,
73+
"gitea admin regenerate keys",
74+
"gitea doctor --run authorized_keys --fix")
75+
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`)
76+
}
77+
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
78+
err = models.RewriteAllPublicKeys()
79+
if err != nil {
80+
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
81+
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err)
82+
}
83+
}
84+
return nil
85+
}
86+
87+
func init() {
88+
Register(&Check{
89+
Title: "Check if OpenSSH authorized_keys file is up-to-date",
90+
Name: "authorized-keys",
91+
IsDefault: true,
92+
Run: checkAuthorizedKeys,
93+
Priority: 4,
94+
})
95+
}

modules/doctor/dbconsistency.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package doctor
6+
7+
import (
8+
"context"
9+
10+
"code.gitea.io/gitea/models"
11+
"code.gitea.io/gitea/models/migrations"
12+
"code.gitea.io/gitea/modules/log"
13+
)
14+
15+
func checkDBConsistency(logger log.Logger, autofix bool) error {
16+
// make sure DB version is uptodate
17+
if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
18+
logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
19+
return err
20+
}
21+
22+
// find labels without existing repo or org
23+
count, err := models.CountOrphanedLabels()
24+
if err != nil {
25+
logger.Critical("Error: %v whilst counting orphaned labels")
26+
return err
27+
}
28+
29+
if count > 0 {
30+
if autofix {
31+
if err = models.DeleteOrphanedLabels(); err != nil {
32+
logger.Critical("Error: %v whilst deleting orphaned labels")
33+
return err
34+
}
35+
logger.Info("%d labels without existing repository/organisation deleted", count)
36+
} else {
37+
logger.Warn("%d labels without existing repository/organisation", count)
38+
}
39+
}
40+
41+
// find issues without existing repository
42+
count, err = models.CountOrphanedIssues()
43+
if err != nil {
44+
logger.Critical("Error: %v whilst counting orphaned issues")
45+
return err
46+
}
47+
if count > 0 {
48+
if autofix {
49+
if err = models.DeleteOrphanedIssues(); err != nil {
50+
logger.Critical("Error: %v whilst deleting orphaned issues")
51+
return err
52+
}
53+
logger.Info("%d issues without existing repository deleted", count)
54+
} else {
55+
logger.Warn("%d issues without existing repository", count)
56+
}
57+
}
58+
59+
// find pulls without existing issues
60+
count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
61+
if err != nil {
62+
logger.Critical("Error: %v whilst counting orphaned objects")
63+
return err
64+
}
65+
if count > 0 {
66+
if autofix {
67+
if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil {
68+
logger.Critical("Error: %v whilst deleting orphaned objects")
69+
return err
70+
}
71+
logger.Info("%d pull requests without existing issue deleted", count)
72+
} else {
73+
logger.Warn("%d pull requests without existing issue", count)
74+
}
75+
}
76+
77+
// find tracked times without existing issues/pulls
78+
count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id")
79+
if err != nil {
80+
logger.Critical("Error: %v whilst counting orphaned objects")
81+
return err
82+
}
83+
if count > 0 {
84+
if autofix {
85+
if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil {
86+
logger.Critical("Error: %v whilst deleting orphaned objects")
87+
return err
88+
}
89+
logger.Info("%d tracked times without existing issue deleted", count)
90+
} else {
91+
logger.Warn("%d tracked times without existing issue", count)
92+
}
93+
}
94+
95+
// find null archived repositories
96+
count, err = models.CountNullArchivedRepository()
97+
if err != nil {
98+
logger.Critical("Error: %v whilst counting null archived repositories")
99+
return err
100+
}
101+
if count > 0 {
102+
if autofix {
103+
updatedCount, err := models.FixNullArchivedRepository()
104+
if err != nil {
105+
logger.Critical("Error: %v whilst fixing null archived repositories")
106+
return err
107+
}
108+
logger.Info("%d repositories with null is_archived updated", updatedCount)
109+
} else {
110+
logger.Warn("%d repositories with null is_archived", count)
111+
}
112+
}
113+
114+
// TODO: function to recalc all counters
115+
116+
return nil
117+
}
118+
119+
func init() {
120+
Register(&Check{
121+
Title: "Check consistency of database",
122+
Name: "check-db-consistency",
123+
IsDefault: false,
124+
Run: checkDBConsistency,
125+
Priority: 3,
126+
})
127+
}

0 commit comments

Comments
 (0)