mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-21 00:01:16 -04:00
Compare commits
5 Commits
993178b45f
...
aabcf2d7ad
Author | SHA1 | Date | |
---|---|---|---|
|
aabcf2d7ad | ||
|
6919a02ab7 | ||
|
1848858a1e | ||
|
a398089301 | ||
|
8885108c42 |
70
modules/doctor/repository.go
Normal file
70
modules/doctor/repository.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package doctor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error {
|
||||
test := &consistencyCheck{
|
||||
Name: "Repos with no existing owner",
|
||||
Counter: countOrphanedRepos,
|
||||
Fixer: deleteOrphanedRepos,
|
||||
FixedMessage: "Deleted all content related to orphaned repos",
|
||||
}
|
||||
return test.Run(ctx, logger, autofix)
|
||||
}
|
||||
|
||||
// countOrphanedRepos count repository where user of owner_id do not exist
|
||||
func countOrphanedRepos(ctx context.Context) (int64, error) {
|
||||
return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=user.id")
|
||||
}
|
||||
|
||||
// deleteOrphanedRepos delete repository where user of owner_id do not exist
|
||||
func deleteOrphanedRepos(ctx context.Context) (int64, error) {
|
||||
batchSize := db.MaxBatchInsertSize("repository")
|
||||
e := db.GetEngine(ctx)
|
||||
var deleted int64
|
||||
adminUser := &user_model.User{IsAdmin: true}
|
||||
|
||||
for {
|
||||
var ids []int64
|
||||
if err := e.Table("`repository`").
|
||||
Join("LEFT", "`user`", "repository.owner_id=user.id").
|
||||
Where(builder.IsNull{"`user`.id"}).
|
||||
Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil {
|
||||
return deleted, err
|
||||
}
|
||||
|
||||
// if we don't get ids we have deleted them all
|
||||
if len(ids) == 0 {
|
||||
return deleted, nil
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, 0, id, true); err != nil {
|
||||
return deleted, err
|
||||
}
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(&Check{
|
||||
Title: "Deleted all content related to orphaned repos",
|
||||
Name: "delete-orphaned-repos",
|
||||
IsDefault: false,
|
||||
Run: handleDeleteOrphanedRepos,
|
||||
Priority: 4,
|
||||
})
|
||||
}
|
@ -74,27 +74,31 @@ func ActionIcon(opType activities_model.ActionType) string {
|
||||
switch opType {
|
||||
case activities_model.ActionCreateRepo, activities_model.ActionTransferRepo, activities_model.ActionRenameRepo:
|
||||
return "repo"
|
||||
case activities_model.ActionCommitRepo, activities_model.ActionPushTag, activities_model.ActionDeleteTag, activities_model.ActionDeleteBranch:
|
||||
case activities_model.ActionCommitRepo:
|
||||
return "git-commit"
|
||||
case activities_model.ActionCreateIssue:
|
||||
return "issue-opened"
|
||||
case activities_model.ActionCreatePullRequest:
|
||||
return "git-pull-request"
|
||||
case activities_model.ActionCommentIssue, activities_model.ActionCommentPull:
|
||||
return "comment-discussion"
|
||||
case activities_model.ActionDeleteBranch:
|
||||
return "git-branch"
|
||||
case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest:
|
||||
return "git-merge"
|
||||
case activities_model.ActionCloseIssue, activities_model.ActionClosePullRequest:
|
||||
case activities_model.ActionCreatePullRequest:
|
||||
return "git-pull-request"
|
||||
case activities_model.ActionClosePullRequest:
|
||||
return "git-pull-request-closed"
|
||||
case activities_model.ActionCreateIssue:
|
||||
return "issue-opened"
|
||||
case activities_model.ActionCloseIssue:
|
||||
return "issue-closed"
|
||||
case activities_model.ActionReopenIssue, activities_model.ActionReopenPullRequest:
|
||||
return "issue-reopened"
|
||||
case activities_model.ActionCommentIssue, activities_model.ActionCommentPull:
|
||||
return "comment-discussion"
|
||||
case activities_model.ActionMirrorSyncPush, activities_model.ActionMirrorSyncCreate, activities_model.ActionMirrorSyncDelete:
|
||||
return "mirror"
|
||||
case activities_model.ActionApprovePullRequest:
|
||||
return "check"
|
||||
case activities_model.ActionRejectPullRequest:
|
||||
return "diff"
|
||||
case activities_model.ActionPublishRelease:
|
||||
return "file-diff"
|
||||
case activities_model.ActionPublishRelease, activities_model.ActionPushTag, activities_model.ActionDeleteTag:
|
||||
return "tag"
|
||||
case activities_model.ActionPullReviewDismissed:
|
||||
return "x"
|
||||
|
@ -1443,10 +1443,10 @@ func Routes() *web.Route {
|
||||
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
m.Group("/teams", func() {
|
||||
m.Get("", reqToken(), org.ListTeams)
|
||||
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
m.Get("/search", reqToken(), org.SearchTeam)
|
||||
}, reqOrgMembership())
|
||||
m.Get("", org.ListTeams)
|
||||
m.Post("", reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
m.Get("/search", org.SearchTeam)
|
||||
}, reqToken(), reqOrgMembership())
|
||||
m.Group("/labels", func() {
|
||||
m.Get("", org.ListLabels)
|
||||
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
||||
|
@ -33,7 +33,7 @@ import (
|
||||
|
||||
// DeleteRepository deletes a repository for a user or organization.
|
||||
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
|
||||
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, repoID int64) error {
|
||||
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, repoID int64, ignoreOrgTeams ...bool) error {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -53,10 +53,13 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r
|
||||
return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
|
||||
}
|
||||
|
||||
// In case is a organization.
|
||||
org, err := user_model.GetUserByID(ctx, uid)
|
||||
if err != nil {
|
||||
return err
|
||||
// In case owner is a organization, we have to change repo specific teams
|
||||
// if ignoreOrgTeams is not true
|
||||
var org *user_model.User
|
||||
if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] {
|
||||
if org, err = user_model.GetUserByID(ctx, uid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
repo := &repo_model.Repository{OwnerID: uid}
|
||||
@ -95,7 +98,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r
|
||||
}
|
||||
}
|
||||
|
||||
if org.IsOrganization() {
|
||||
if org != nil && org.IsOrganization() {
|
||||
teams, err := organization.FindOrgTeams(ctx, org.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -78,20 +78,23 @@
|
||||
{{$reviewer := index .GetIssueInfos 1}}
|
||||
{{ctx.Locale.Tr "action.review_dismissed" ((printf "%s/pulls/%s" (.GetRepoLink ctx) $index) |Escape) $index ((.ShortRepoPath ctx)|Escape) $reviewer | Str2html}}
|
||||
{{end}}
|
||||
{{TimeSince .GetCreate ctx.Locale}}
|
||||
</div>
|
||||
{{if .GetOpType.InActions "commit_repo" "mirror_sync_push"}}
|
||||
{{$push := ActionContent2Commits .}}
|
||||
{{$repoLink := (.GetRepoLink ctx)}}
|
||||
{{range $push.Commits}}
|
||||
{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
|
||||
<div class="flex-text-block">
|
||||
<img class="ui avatar" src="{{$push.AvatarLink $.Context .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
|
||||
<a class="gt-mono" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
|
||||
<span class="text truncate light grey">
|
||||
{{RenderCommitMessage $.Context .Message $repoLink $.ComposeMetas}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="gt-df gt-fc gt-gap-2">
|
||||
{{range $push.Commits}}
|
||||
{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
|
||||
<div class="flex-text-block">
|
||||
<img class="ui avatar" src="{{$push.AvatarLink $.Context .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
|
||||
<a class="ui sha label" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
|
||||
<span class="text truncate">
|
||||
{{RenderCommitMessage $.Context .Message $repoLink $.ComposeMetas}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if and (gt $push.Len 1) $push.CompareURL}}
|
||||
<a href="{{AppSubUrl}}/{{$push.CompareURL}}">{{ctx.Locale.Tr "action.compare_commits" $push.Len}} »</a>
|
||||
{{end}}
|
||||
@ -103,17 +106,16 @@
|
||||
<a href="{{.GetCommentLink ctx}}" class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</a>
|
||||
{{$comment := index .GetIssueInfos 1}}
|
||||
{{if gt (len $comment) 0}}
|
||||
<div class="flex-item-body">{{$comment | RenderEmoji $.Context | RenderCodeBlock}}</div>
|
||||
<div class="markup gt-font-14">{{RenderMarkdownToHtml ctx $comment}}</div>
|
||||
{{end}}
|
||||
{{else if .GetOpType.InActions "merge_pull_request"}}
|
||||
<div class="flex-item-body">{{index .GetIssueInfos 1}}</div>
|
||||
<div class="flex-item-body text black">{{index .GetIssueInfos 1}}</div>
|
||||
{{else if .GetOpType.InActions "close_issue" "reopen_issue" "close_pull_request" "reopen_pull_request"}}
|
||||
<span class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</span>
|
||||
{{else if .GetOpType.InActions "pull_review_dismissed"}}
|
||||
<div class="flex-item-body">{{ctx.Locale.Tr "action.review_dismissed_reason"}}</div>
|
||||
<div class="flex-item-body">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</div>
|
||||
<div class="flex-item-body text black">{{ctx.Locale.Tr "action.review_dismissed_reason"}}</div>
|
||||
<div class="flex-item-body text black">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</div>
|
||||
{{end}}
|
||||
<div class="flex-item-body">{{TimeSince .GetCreate ctx.Locale}}</div>
|
||||
</div>
|
||||
<div class="flex-item-trailing">
|
||||
{{svg (printf "octicon-%s" (ActionIcon .GetOpType)) 32 "text grey gt-mr-2"}}
|
||||
|
@ -69,7 +69,6 @@
|
||||
}
|
||||
|
||||
.flex-item .flex-item-body {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
@ -126,7 +126,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="store.fileTreeIsVisible" class="gt-mr-3">
|
||||
<div v-if="store.fileTreeIsVisible" class="diff-file-tree-items">
|
||||
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
|
||||
<DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item"/>
|
||||
<div v-if="store.isIncomplete" class="gt-pt-2">
|
||||
@ -134,3 +134,11 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.diff-file-tree-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -58,11 +58,14 @@ a, a:hover {
|
||||
}
|
||||
|
||||
.sub-items {
|
||||
padding-left: 9px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.item-file {
|
||||
margin-left: 20px;
|
||||
.sub-items .item-file {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.item-file.selected {
|
||||
@ -80,7 +83,7 @@ a, a:hover {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
padding: 2px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
.item-file:hover,
|
||||
|
Loading…
x
Reference in New Issue
Block a user