diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index fa72f9b647da0..ccc1fe41fbd97 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -321,3 +321,20 @@ created_unix: 946684830 updated_unix: 978307200 is_locked: false + +- + id: 20 + repo_id: 23 + index: 1 + poster_id: 2 + original_author_id: 0 + name: issue for pr + content: content + milestone_id: 0 + priority: 0 + is_closed: false + is_pull: true + num_comments: 0 + created_unix: 978307210 + updated_unix: 978307210 + is_locked: false diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index e5589ac703d77..396bdba88cbc5 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -89,3 +89,12 @@ base_branch: main merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6 has_merged: false + +- + id: 8 + type: 0 # gitea pull request + status: 2 # mergable + issue_id: 20 + index: 1 + head_repo_id: 23 + base_repo_id: 23 \ No newline at end of file diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index c63b7ebd48170..373c1caa6257a 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -679,7 +679,7 @@ num_forks: 0 num_issues: 0 num_closed_issues: 0 - num_pulls: 0 + num_pulls: 1 num_closed_pulls: 0 num_milestones: 0 num_closed_milestones: 0 diff --git a/models/fixtures/review.yml b/models/fixtures/review.yml index dda13dc468e47..f964c6ac06412 100644 --- a/models/fixtures/review.yml +++ b/models/fixtures/review.yml @@ -132,3 +132,41 @@ content: "singular review from org6 and final review for this pr" updated_unix: 946684831 created_unix: 946684831 + +- + id: 16 + type: 4 + reviewer_id: 20 + issue_id: 20 + content: "review request for user20" + updated_unix: 946684832 + created_unix: 946684832 + +- + id: 17 + type: 1 + reviewer_id: 20 + issue_id: 20 + content: "review approved by user20" + updated_unix: 946684833 + created_unix: 946684833 +- + id: 18 + type: 4 + reviewer_id: 0 + reviewer_team_id: 5 + issue_id: 20 + content: "review request for team5" + updated_unix: 946684834 + created_unix: 946684834 + +- + id: 19 + type: 4 + reviewer_id: 15 + reviewer_team_id: 0 + issue_id: 20 + content: "review request for user15" + updated_unix: 946684835 + created_unix: 946684835 + diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml index 65326eedbf476..295e51e39ce94 100644 --- a/models/fixtures/team.yml +++ b/models/fixtures/team.yml @@ -93,7 +93,7 @@ name: review_team authorize: 1 # read num_repos: 1 - num_members: 2 + num_members: 3 includes_all_repositories: false can_create_org_repo: false diff --git a/models/fixtures/team_user.yml b/models/fixtures/team_user.yml index feace5f2a531d..a5f1e9fd92aaf 100644 --- a/models/fixtures/team_user.yml +++ b/models/fixtures/team_user.yml @@ -123,3 +123,9 @@ org_id: 36 team_id: 20 uid: 5 + +- + id: 22 + org_id: 17 + team_id: 9 + uid: 15 diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index 5ed1003749749..5be35f4b113c7 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -315,6 +315,11 @@ type WhitelistOptions struct { // This function also performs check if whitelist user and team's IDs have been changed // to avoid unnecessary whitelist delete and regenerate. func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + if err = repo.LoadOwner(ctx); err != nil { return fmt.Errorf("LoadOwner: %v", err) } @@ -445,9 +450,14 @@ func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, curre } // DeleteProtectedBranch removes ProtectedBranch relation between the user and repository. -func DeleteProtectedBranch(ctx context.Context, repoID, id int64) (err error) { +func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id int64) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + protectedBranch := &ProtectedBranch{ - RepoID: repoID, + RepoID: repo.ID, ID: id, } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 5d40b447042c3..5c05ead6879e7 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -362,14 +362,21 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) From("team_user"). Where(builder.Eq{"team_user.uid": reviewRequestedID}) + // if the review is approved or rejected, it should not be shown in the review requested list + maxReview := builder.Select("MAX(r.id)"). + From("review as r"). + Where(builder.In("r.type", []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest})). + GroupBy("r.issue_id, r.reviewer_id, r.reviewer_team_id") + subQuery := builder.Select("review.issue_id"). From("review"). Where(builder.And( - builder.In("review.type", []ReviewType{ReviewTypeRequest, ReviewTypeReject, ReviewTypeApprove}), + builder.Eq{"review.type": ReviewTypeRequest}, builder.Or( builder.Eq{"review.reviewer_id": reviewRequestedID}, builder.In("review.reviewer_team_id", existInTeamQuery), ), + builder.In("review.id", maxReview), )) return sess.Where("issue.poster_id <> ?", reviewRequestedID). And(builder.In("issue.id", subQuery)) diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index b7fa7eff1c150..513ae241bc9cc 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -403,7 +403,7 @@ func TestCountIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{}) assert.NoError(t, err) - assert.EqualValues(t, 19, count) + assert.EqualValues(t, 20, count) } func TestIssueLoadAttributes(t *testing.T) { diff --git a/models/issues/issue_user.go b/models/issues/issue_user.go index d053b1d54350b..24bb74648d9ce 100644 --- a/models/issues/issue_user.go +++ b/models/issues/issue_user.go @@ -15,7 +15,7 @@ import ( type IssueUser struct { ID int64 `xorm:"pk autoincr"` UID int64 `xorm:"INDEX"` // User ID. - IssueID int64 + IssueID int64 `xorm:"INDEX"` IsRead bool IsMentioned bool } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 3524077ea4b7c..38fff37bed066 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -534,6 +534,8 @@ var migrations = []Migration{ NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), // v276 -> v277 NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors), + // v277 -> v278 + NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_21/v277.go b/models/migrations/v1_21/v277.go new file mode 100644 index 0000000000000..12529160b754b --- /dev/null +++ b/models/migrations/v1_21/v277.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "xorm.io/xorm" +) + +func AddIndexToIssueUserIssueID(x *xorm.Engine) error { + type IssueUser struct { + IssueID int64 `xorm:"INDEX"` + } + + return x.Sync(new(IssueUser)) +} diff --git a/models/repo/repo.go b/models/repo/repo.go index 5ebc7bfc24208..0b0c029993a9b 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -47,6 +47,14 @@ func (err ErrUserDoesNotHaveAccessToRepo) Unwrap() error { return util.ErrPermissionDenied } +type ErrRepoIsArchived struct { + Repo *Repository +} + +func (err ErrRepoIsArchived) Error() string { + return fmt.Sprintf("%s is archived", err.Repo.LogString()) +} + var ( reservedRepoNames = []string{".", "..", "-"} reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"} @@ -654,6 +662,14 @@ func (repo *Repository) GetTrustModel() TrustModelType { return trustModel } +// MustNotBeArchived returns ErrRepoIsArchived if the repo is archived +func (repo *Repository) MustNotBeArchived() error { + if repo.IsArchived { + return ErrRepoIsArchived{Repo: repo} + } + return nil +} + // __________ .__ __ // \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | diff --git a/modules/context/api.go b/modules/context/api.go index 044ec51b56599..a46af6ed78232 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -101,6 +101,12 @@ type APIRedirect struct{} // swagger:response string type APIString string +// APIRepoArchivedError is an error that is raised when an archived repo should be modified +// swagger:response repoArchivedError +type APIRepoArchivedError struct { + APIError +} + // ServerError responds with error message, status is 500 func (ctx *APIContext) ServerError(title string, err error) { ctx.Error(http.StatusInternalServerError, title, err) diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index 0e36d21313737..7241f6313c891 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -180,6 +180,21 @@ func searchIssueByID(t *testing.T) { }, []int64{11, 6, 5, 3, 2, 1}, }, + { + // issue 20 request user 15 and team 5 which user 15 belongs to + // the review request number of issue 20 should be 1 + SearchOptions{ + ReviewRequestedID: int64Pointer(15), + }, + []int64{12, 20}, + }, + { + // user 20 approved the issue 20, so return nothing + SearchOptions{ + ReviewRequestedID: int64Pointer(20), + }, + []int64{}, + }, } for _, test := range tests { @@ -206,7 +221,7 @@ func searchIssueIsPull(t *testing.T) { SearchOptions{ IsPull: util.OptionalBoolTrue, }, - []int64{12, 11, 19, 9, 8, 3, 2}, + []int64{12, 11, 20, 19, 9, 8, 3, 2}, }, } for _, test := range tests { @@ -227,7 +242,7 @@ func searchIssueIsClosed(t *testing.T) { SearchOptions{ IsClosed: util.OptionalBoolFalse, }, - []int64{17, 16, 15, 14, 13, 12, 11, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, }, { SearchOptions{ @@ -293,7 +308,7 @@ func searchIssueByLabelID(t *testing.T) { SearchOptions{ ExcludedLabelIDs: []int64{1}, }, - []int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, }, } for _, test := range tests { @@ -317,7 +332,7 @@ func searchIssueByTime(t *testing.T) { SearchOptions{ UpdatedAfterUnix: int64Pointer(0), }, - []int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, }, } for _, test := range tests { @@ -338,7 +353,7 @@ func searchIssueWithOrder(t *testing.T) { SearchOptions{ SortBy: internal.SortByCreatedAsc, }, - []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 11, 12, 13, 14, 15, 16, 17}, + []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17}, }, } for _, test := range tests { @@ -393,7 +408,7 @@ func searchIssueWithPaginator(t *testing.T) { }, }, []int64{17, 16, 15, 14, 13}, - 19, + 20, }, } for _, test := range tests { diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index c78c6811b44b4..7ded66b5e896f 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -180,6 +180,7 @@ network_error=ネットワークエラー [startpage] app_desc=自分で立てる、超簡単 Git サービス install=簡単インストール +install_desc=シンプルに、プラットフォームに応じてバイナリを実行したり、Dockerで動かしたり、パッケージを使うだけ。 platform=クロスプラットフォーム platform_desc=GiteaはGoでコンパイルできる環境ならどこでも動きます: Windows、macOS、Linux、ARM等々、好きなものを選んでください! lightweight=軽量 @@ -377,6 +378,7 @@ email_not_associate=このメールアドレスは、どのアカウントにも send_reset_mail=アカウント回復メールを送信 reset_password=アカウントの回復 invalid_code=確認コードが無効か期限切れです。 +invalid_code_forgot_password=確認コードは無効または期限切れです。 新しいセッションを開始するにはここをクリックしてください。 invalid_password=アカウントの作成に使用されたパスワードと一致しません。 reset_password_helper=アカウント回復 reset_password_wrong_user=あなたは %s でサインイン中ですが、アカウント回復のリンクは %s のものです。 @@ -678,6 +680,7 @@ choose_new_avatar=新しいアバターを選択 update_avatar=アバターを更新 delete_current_avatar=現在のアバターを削除 uploaded_avatar_not_a_image=アップロードしたファイルは画像ファイルではありません。 +uploaded_avatar_is_too_big=アップロードされたファイルサイズ(%d KiB) が最大サイズ(%d KiB) を超えています。 update_avatar_success=アバターを更新しました。 update_user_avatar_success=ユーザーのアバターを更新しました。 @@ -967,6 +970,7 @@ trust_model_helper_collaborator_committer=共同作業者+コミッター: 共 trust_model_helper_default=デフォルト: このシステムのデフォルトのトラストモデルを使用します create_repo=リポジトリを作成 default_branch=デフォルトブランチ +default_branch_label=デフォルト default_branch_helper=デフォルトブランチはプルリクエストとコードコミットのベースブランチとなります。 mirror_prune=Prune mirror_prune_desc=不要になった古いリモートトラッキング参照を削除 @@ -1466,9 +1470,18 @@ issues.ref_reopening_from=`が%[4]s、プルリクエストが issues.ref_closed_from=`が%[4]s、このイシューをクローズ %[2]s` issues.ref_reopened_from=`が%[4]s、このイシューを再オープン %[2]s` issues.ref_from=` %[1]s にて` -issues.author=著作者 +issues.author=作成者 +issues.author_helper=このユーザーは作成者です。 issues.role.owner=オーナー +issues.role.owner_helper=このユーザーはこのリポジトリの所有者です。 issues.role.member=メンバー +issues.role.member_helper=このユーザーはこのリポジトリを所有している組織のメンバーです。 +issues.role.collaborator=共同作業者 +issues.role.collaborator_helper=このユーザーはリポジトリ上で共同作業するように招待されています。 +issues.role.first_time_contributor=初めての貢献者 +issues.role.first_time_contributor_helper=これは、このユーザーのリポジトリへの最初の貢献です。 +issues.role.contributor=貢献者 +issues.role.contributor_helper=このユーザーは以前にリポジトリにコミットしています。 issues.re_request_review=レビューを再依頼 issues.is_stale=このレビューのあと、このPRに変更がありました issues.remove_request_review=レビュー依頼を取り消し @@ -1727,6 +1740,7 @@ pulls.rebase_conflict_summary=エラーメッセージ pulls.unrelated_histories=マージ失敗: マージHEADとベースには共通する履歴がありません。 ヒント: 別のストラテジーを試してみてください pulls.merge_out_of_date=マージ失敗: マージの生成中にベースが更新されました。 ヒント: もう一度試してみてください pulls.head_out_of_date=マージ失敗: マージの生成中に head が更新されました。 ヒント: もう一度試してみてください +pulls.has_merged=失敗: プルリクエストはマージされていました。再度マージしたり、ターゲットブランチを変更することはできません。 pulls.push_rejected=マージ失敗: プッシュは拒否されました。 このリポジトリのGitフックを見直してください。 pulls.push_rejected_summary=拒否メッセージ全体: pulls.push_rejected_no_message=マージ失敗: プッシュは拒否され、リモートからのメッセージはありません。
このリポジトリのGitフックを見直してください @@ -1792,6 +1806,8 @@ milestones.edit_success=マイルストーン "%s" を更新しました。 milestones.deletion=マイルストーンの削除 milestones.deletion_desc=マイルストーンを削除すると、関連するすべてのイシューから除去されます。 続行しますか? milestones.deletion_success=マイルストーンを削除しました。 +milestones.filter_sort.earliest_due_data=期日が早い順 +milestones.filter_sort.latest_due_date=期日が遅い順 milestones.filter_sort.least_complete=消化率の低い順 milestones.filter_sort.most_complete=消化率の高い順 milestones.filter_sort.most_issues=イシューの多い順 @@ -2289,6 +2305,7 @@ settings.tags.protection.allowed.teams=許可するチーム settings.tags.protection.allowed.noone=なし settings.tags.protection.create=タグを保護 settings.tags.protection.none=タグは保護されていません。 +settings.tags.protection.pattern.description=ひとつのタグ名か、複数のタグにマッチするglobパターンまたは正規表現を使用できます。 詳しくはタグの保護ガイド をご覧ください。 settings.bot_token=Botトークン settings.chat_id=チャットID settings.matrix.homeserver_url=ホームサーバー URL @@ -2680,6 +2697,7 @@ dashboard.reinit_missing_repos=レコードが存在するが見当たらない dashboard.sync_external_users=外部ユーザーデータの同期 dashboard.cleanup_hook_task_table=hook_taskテーブルのクリーンアップ dashboard.cleanup_packages=期限切れパッケージのクリーンアップ +dashboard.cleanup_actions=Actionsの期限切れのログとアーティファクトのクリーンアップ dashboard.server_uptime=サーバーの稼働時間 dashboard.current_goroutine=現在のGoroutine数 dashboard.current_memory_usage=現在のメモリ使用量 @@ -2717,6 +2735,7 @@ dashboard.gc_lfs=LFSメタオブジェクトのガベージコレクション dashboard.stop_zombie_tasks=ゾンビタスクを停止 dashboard.stop_endless_tasks=終わらないタスクを停止 dashboard.cancel_abandoned_jobs=放置されたままのジョブをキャンセル +dashboard.start_schedule_tasks=スケジュールタスクを開始 users.user_manage_panel=ユーザーアカウント管理 users.new_account=ユーザーアカウントを作成 @@ -2725,6 +2744,9 @@ users.full_name=フルネーム users.activated=アクティベート済み users.admin=管理者 users.restricted=制限あり +users.reserved=予約済み +users.bot=Bot +users.remote=リモート users.2fa=2FA users.repos=リポジトリ users.created=作成日 @@ -2771,6 +2793,7 @@ users.list_status_filter.is_prohibit_login=ログインを禁止 users.list_status_filter.not_prohibit_login=ログインを許可 users.list_status_filter.is_2fa_enabled=2要素認証有効 users.list_status_filter.not_2fa_enabled=2要素認証無効 +users.details=ユーザーの詳細 emails.email_manage_panel=ユーザーメールアドレスの管理 emails.primary=プライマリー @@ -2806,6 +2829,7 @@ repos.size=サイズ packages.package_manage_panel=パッケージ管理 packages.total_size=合計サイズ: %s packages.unreferenced_size=非参照サイズ: %s +packages.cleanup=期限切れデータを掃除する packages.owner=オーナー packages.creator=作成者 packages.name=名前 @@ -2816,10 +2840,12 @@ packages.size=サイズ packages.published=配布 defaulthooks=デフォルトWebhook +defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイドをご覧下さい。 defaulthooks.add_webhook=デフォルトWebhookの追加 defaulthooks.update_webhook=デフォルトWebhookの更新 systemhooks=システムWebhook +systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイドをご覧下さい。 systemhooks.add_webhook=システムWebhookを追加 systemhooks.update_webhook=システムWebhookを更新 @@ -2912,6 +2938,7 @@ auths.sspi_default_language=ユーザーのデフォルトの言語 auths.sspi_default_language_helper=SSPI認証処理によって自動的に作成されるユーザーのデフォルトの言語です。 言語を自動検出する方が良い場合は空のままにしてください。 auths.tips=ヒント auths.tips.oauth2.general=OAuth2認証 +auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります: auths.tip.oauth2_provider=OAuth2プロバイダー auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/<あなたのユーザー名>/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。 auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。 @@ -2923,6 +2950,7 @@ auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコン auths.tip.openid_connect=OpenID Connect DiscoveryのURL (/.well-known/openid-configuration) をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。 +auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります auths.tip.yandex=`https://oauth.yandex.com/client/new で新しいアプリケーションを作成してください。 "Yandex.Passport API" セクションで次の項目を許可します: "Access to email address"、"Access to user avatar"、"Access to username, first name and surname, gender"` auths.tip.mastodon=認証したいMastodonインスタンスのカスタムURLを入力してください (入力しない場合はデフォルトのURLを使用します) auths.edit=認証ソースの編集 @@ -2952,6 +2980,7 @@ config.disable_router_log=ルーターのログが無効 config.run_user=実行ユーザー名 config.run_mode=実行モード config.git_version=Gitバージョン +config.app_data_path=Appデータパス config.repo_root_path=リポジトリのルートパス config.lfs_root_path=LFSルートパス config.log_file_root_path=ログの保存先パス diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 763d56ecd2622..dc1f914922a10 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -675,7 +675,7 @@ func mustEnableWiki(ctx *context.APIContext) { func mustNotBeArchived(ctx *context.APIContext) { if ctx.Repo.Repository.IsArchived { - ctx.NotFound() + ctx.Error(http.StatusLocked, "RepoArchived", fmt.Errorf("%s is archived", ctx.Repo.Repository.LogString())) return } } @@ -1108,23 +1108,23 @@ func Routes() *web.Route { m.Group("/branches", func() { m.Get("", repo.ListBranches) m.Get("/*", repo.GetBranch) - m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), repo.DeleteBranch) - m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch) + m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteBranch) + m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateBranchRepoOption{}), repo.CreateBranch) }, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode)) m.Group("/branch_protections", func() { m.Get("", repo.ListBranchProtections) - m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection) + m.Post("", bind(api.CreateBranchProtectionOption{}), mustNotBeArchived, repo.CreateBranchProtection) m.Group("/{name}", func() { m.Get("", repo.GetBranchProtection) - m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection) + m.Patch("", bind(api.EditBranchProtectionOption{}), mustNotBeArchived, repo.EditBranchProtection) m.Delete("", repo.DeleteBranchProtection) }) }, reqToken(), reqAdmin()) m.Group("/tags", func() { m.Get("", repo.ListTags) m.Get("/*", repo.GetTag) - m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag) - m.Delete("/*", reqToken(), repo.DeleteTag) + m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), repo.CreateTag) + m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteTag) }, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true)) m.Group("/keys", func() { m.Combo("").Get(repo.ListDeployKeys). @@ -1245,15 +1245,15 @@ func Routes() *web.Route { m.Get("/tags/{sha}", repo.GetAnnotatedTag) m.Get("/notes/{sha}", repo.GetNote) }, context.ReferencesGitRepo(true), reqRepoReader(unit.TypeCode)) - m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch) + m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), mustNotBeArchived, repo.ApplyDiffPatch) m.Group("/contents", func() { m.Get("", repo.GetContentsList) - m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, repo.ChangeFiles) + m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.ChangeFiles) m.Get("/*", repo.GetContents) m.Group("/*", func() { - m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, repo.CreateFile) - m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, repo.UpdateFile) - m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, repo.DeleteFile) + m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.CreateFile) + m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.UpdateFile) + m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.DeleteFile) }, reqToken()) }, reqRepoReader(unit.TypeCode)) m.Get("/signing-key.gpg", misc.SigningKey) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index 519572ee51882..83cbfe68d0ff8 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -248,7 +248,7 @@ func CreateTeam(ctx *context.APIContext) { return } - apiTeam, err := convert.ToTeam(ctx, team) + apiTeam, err := convert.ToTeam(ctx, team, true) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index c851525c0f023..583b591d10b07 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -117,17 +117,13 @@ func DeleteBranch(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" - + // "423": + // "$ref": "#/responses/repoArchivedError" if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") return } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") - return - } - if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") return @@ -157,10 +153,6 @@ func DeleteBranch(ctx *context.APIContext) { } } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "IsArchived", fmt.Errorf("can not delete branch of an archived repository")) - return - } if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "IsMirrored", fmt.Errorf("can not delete branch of an mirror repository")) return @@ -216,17 +208,14 @@ func CreateBranch(ctx *context.APIContext) { // description: The old branch does not exist. // "409": // description: The branch with the same name already exists. + // "423": + // "$ref": "#/responses/repoArchivedError" if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") return } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") - return - } - if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") return @@ -519,6 +508,8 @@ func CreateBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateBranchProtectionOption) repo := ctx.Repo.Repository @@ -727,6 +718,8 @@ func EditBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.EditBranchProtectionOption) repo := ctx.Repo.Repository bpName := ctx.Params(":name") @@ -1004,7 +997,7 @@ func DeleteBranchProtection(ctx *context.APIContext) { return } - if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, bp.ID); err != nil { + if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, bp.ID); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteProtectedBranch", err) return } diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index ea311c3202924..94e634461c278 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -450,6 +450,8 @@ func ChangeFiles(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.ChangeFilesOptions) @@ -550,6 +552,8 @@ func CreateFile(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.CreateFileOptions) @@ -646,6 +650,8 @@ func UpdateFile(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.UpdateFileOptions) if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty")) @@ -806,6 +812,8 @@ func DeleteFile(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.DeleteFileOptions) if !canWriteFiles(ctx, apiOpts.BranchName) { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 05dfa45e3d94c..2bced1f233e78 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -631,6 +631,8 @@ func CreateIssue(ctx *context.APIContext) { // "$ref": "#/responses/error" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateIssueOption) var deadlineUnix timeutil.TimeStamp if form.Deadline != nil && ctx.Repo.CanWrite(unit.TypeIssues) { diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index 60e554990f864..b4768004adad3 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -153,6 +153,8 @@ func CreateIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" issue := getIssueFromContext(ctx) if issue == nil { @@ -238,6 +240,8 @@ func EditIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/Attachment" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" attachment := getIssueAttachmentSafeWrite(ctx) if attachment == nil { @@ -292,6 +296,8 @@ func DeleteIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" attachment := getIssueAttachmentSafeWrite(ctx) if attachment == nil { diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index c9179e69db626..8ef968c128d5f 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -358,6 +358,8 @@ func CreateIssueComment(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateIssueCommentOption) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { @@ -486,7 +488,8 @@ func EditIssueComment(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.EditIssueCommentOption) editIssueComment(ctx, *form) } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index c30e8278dbc98..63ed51c72d903 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -156,6 +156,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" // Check if comment exists and load comment comment := getIssueCommentSafe(ctx) @@ -245,7 +247,8 @@ func EditIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/Attachment" // "404": // "$ref": "#/responses/error" - + // "423": + // "$ref": "#/responses/repoArchivedError" attach := getIssueCommentAttachmentSafeWrite(ctx) if attach == nil { return @@ -297,7 +300,8 @@ func DeleteIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/error" - + // "423": + // "$ref": "#/responses/repoArchivedError" attach := getIssueCommentAttachmentSafeWrite(ctx) if attach == nil { return diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index 5ea3836da1afc..9571532800d85 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -187,6 +187,8 @@ func CreateIssueDependency(ctx *context.APIContext) { // "$ref": "#/responses/Issue" // "404": // description: the issue does not exist + // "423": + // "$ref": "#/responses/repoArchivedError" // We want to make <:index> depend on
, i.e. <:index> is the target target := getParamsIssue(ctx) @@ -246,6 +248,8 @@ func RemoveIssueDependency(ctx *context.APIContext) { // "$ref": "#/responses/Issue" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" // We want to make <:index> depend on , i.e. <:index> is the target target := getParamsIssue(ctx) diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index 080908ab7edc1..9b5635d245a0c 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -47,6 +47,8 @@ func ApplyDiffPatch(ctx *context.APIContext) { // "$ref": "#/responses/FileResponse" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions) opts := &files.ApplyDiffPatchOptions{ diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 4f22a059a13c6..1439d48a8eb1c 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -282,6 +282,8 @@ func CreatePullRequest(ctx *context.APIContext) { // "$ref": "#/responses/error" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := *web.GetForm(ctx).(*api.CreatePullRequestOption) if form.Head == form.Base { @@ -741,6 +743,8 @@ func MergePullRequest(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*forms.MergePullRequestForm) @@ -1196,6 +1200,8 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" pullIndex := ctx.ParamsInt64(":index") pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex) diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index 0c0a73698f749..cd29937cb834a 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateTagOption) // If target is not provided use default branch @@ -251,6 +253,8 @@ func DeleteTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "423": + // "$ref": "#/responses/repoArchivedError" tagName := ctx.Params("*") tag, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName) diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 4ea3fbd11d680..8e5ecce310e3e 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -52,6 +52,8 @@ func NewWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateWikiPageOptions) @@ -128,6 +130,8 @@ func EditWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateWikiPageOptions) @@ -234,6 +238,8 @@ func DeleteWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index e0f2294a14f7c..3138f2327b28d 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -285,7 +285,7 @@ func DeleteProtectedBranchRulePost(ctx *context.Context) { return } - if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, ruleID); err != nil { + if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, ruleID); err != nil { ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", rule.RuleName)) ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink)) return diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 4cc093e65debd..fd0f32717c4b6 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1343,7 +1343,7 @@ outer: } } - return diff, err + return diff, nil } // CommentAsDiff returns c.Patch as *Diff diff --git a/services/release/release.go b/services/release/release.go index ac3acc9085934..55cc7bfe2fcb4 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -25,6 +25,16 @@ import ( ) func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { + err := rel.LoadAttributes(ctx) + if err != nil { + return false, err + } + + err = rel.Repo.MustNotBeArchived() + if err != nil { + return false, err + } + var created bool // Only actual create when publish. if !rel.IsDraft { diff --git a/services/repository/branch.go b/services/repository/branch.go index 011dc5568ec0a..3351252200166 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -29,6 +29,11 @@ import ( // CreateNewBranch creates a new repository branch func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldBranchName, branchName string) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + // Check if branch name can be used if err := checkBranchName(ctx, repo, branchName); err != nil { return err @@ -246,6 +251,11 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri // CreateNewBranchFromCommit creates a new repository branch func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, branchName string) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + // Check if branch name can be used if err := checkBranchName(ctx, repo, branchName); err != nil { return err @@ -267,6 +277,11 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo // RenameBranch rename a branch func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, gitRepo *git.Repository, from, to string) (string, error) { + err := repo.MustNotBeArchived() + if err != nil { + return "", err + } + if from == to { return "target_exist", nil } @@ -315,6 +330,11 @@ var ( // DeleteBranch delete branch func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string) error { + err := repo.MustNotBeArchived() + if err != nil { + return err + } + if branchName == repo.DefaultBranch { return ErrBranchIsDefault } diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index fdf0b32f1a1d3..5ef0619636e77 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -95,6 +95,11 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode // ApplyDiffPatch applies a patch to the given repository func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { + err := repo.MustNotBeArchived() + if err != nil { + return nil, err + } + if err := opts.Validate(ctx, repo, doer); err != nil { return nil, err } diff --git a/services/repository/files/update.go b/services/repository/files/update.go index f01092d360d6c..2a08bcbaceac2 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -65,6 +65,11 @@ type RepoFileOptions struct { // ChangeRepoFiles adds, updates or removes multiple files in the given repository func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ChangeRepoFilesOptions) (*structs.FilesResponse, error) { + err := repo.MustNotBeArchived() + if err != nil { + return nil, err + } + // If no branch name is set, assume default branch if opts.OldBranch == "" { opts.OldBranch = repo.DefaultBranch diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 69fae03299a83..c6fbe2f07656e 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -170,7 +170,7 @@ func (d *DingtalkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e func (d *DingtalkPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true) - return createDingtalkPayload(text, text, "view release", p.Release.URL), nil + return createDingtalkPayload(text, text, "view release", p.Release.HTMLURL), nil } func createDingtalkPayload(title, text, singleTitle, singleURL string) *DingtalkPayload { diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index e3122d2f36fca..7289c751f3845 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -238,7 +238,7 @@ func TestDingTalkPayload(t *testing.T) { assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Text) assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Title) assert.Equal(t, "view release", pl.(*DingtalkPayload).ActionCard.SingleTitle) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) }) } diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 204587eca5b1e..b22bb4f91210b 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -253,7 +253,7 @@ func (d *DiscordPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, color := getReleasePayloadInfo(p, noneLinkFormatter, false) - return d.createPayload(p.Sender, text, p.Release.Note, p.Release.URL, color), nil + return d.createPayload(p.Sender, text, p.Release.Note, p.Release.HTMLURL, color), nil } // GetDiscordPayload converts a discord webhook into a DiscordPayload diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index 624d53446a981..6a276e9e874da 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -270,7 +270,7 @@ func TestDiscordPayload(t *testing.T) { assert.Len(t, pl.(*DiscordPayload).Embeds, 1) assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*DiscordPayload).Embeds[0].Title) assert.Equal(t, "Note of first stable release", pl.(*DiscordPayload).Embeds[0].Description) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*DiscordPayload).Embeds[0].URL) assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index 64bd72f5a05a4..a9a8c6b5212c1 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -240,7 +240,7 @@ func pullReleaseTestPayload() *api.ReleasePayload { Target: "master", Title: "First stable release", Note: "Note of first stable release", - URL: "http://localhost:3000/api/v1/repos/test/repo/releases/2", + HTMLURL: "http://localhost:3000/test/repo/releases/tag/v1.0", }, } } diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index df97b43b64ca1..a7f57f97b6a42 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -177,7 +177,7 @@ func (m *MatrixPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e func (m *MatrixPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { senderLink := MatrixLinkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName) title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) - titleLink := MatrixLinkFormatter(p.PullRequest.URL, title) + titleLink := MatrixLinkFormatter(p.PullRequest.HTMLURL, title) repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName) var text string diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 6ad58a6247fd1..dfc1c682895ef 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -290,7 +290,7 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { p.Sender, title, "", - p.Release.URL, + p.Release.HTMLURL, color, &MSTeamsFact{"Tag:", p.Release.TagName}, ), nil diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index 4f378713cc7c6..990a535df5c1a 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -429,7 +429,7 @@ func TestMSTeamsPayload(t *testing.T) { } assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) }) } diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 0cb27bb3dd6dc..75079d0fdf158 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -223,7 +223,7 @@ func (s *SlackPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, er attachments = append(attachments, SlackAttachment{ Color: fmt.Sprintf("%x", color), Title: issueTitle, - TitleLink: p.PullRequest.URL, + TitleLink: p.PullRequest.HTMLURL, Text: attachmentText, }) } diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index c0183dd2b590a..250b539080221 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -79,6 +79,11 @@ func prepareGitPath(gitRepo *git.Repository, wikiPath WebPath) (bool, string, er // updateWikiPage adds a new page or edits an existing page in repository wiki. func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldWikiName, newWikiName WebPath, content, message string, isNew bool) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + if err = validateWebPath(newWikiName); err != nil { return err } @@ -238,6 +243,11 @@ func EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.R // DeleteWikiPage deletes a wiki page identified by its path. func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, wikiName WebPath) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + wikiWorkingPool.CheckIn(fmt.Sprint(repo.ID)) defer wikiWorkingPool.CheckOut(fmt.Sprint(repo.ID)) diff --git a/templates/admin/base/search.tmpl b/templates/admin/base/search.tmpl index 19977f05a9bcc..865cc8830f308 100644 --- a/templates/admin/base/search.tmpl +++ b/templates/admin/base/search.tmpl @@ -9,8 +9,8 @@