You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

846 lines
26 KiB

API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
4 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
4 years ago
Restricted users (#6274) * Restricted users (#4334): initial implementation * Add User.IsRestricted & UI to edit it * Pass user object instead of user id to places where IsRestricted flag matters * Restricted users: maintain access rows for all referenced repos (incl public) * Take logged in user & IsRestricted flag into account in org/repo listings, searches and accesses * Add basic repo access tests for restricted users Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Mention restricted users in the faq Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert unnecessary change `.isUserPartOfOrg` -> `.IsUserPartOfOrg` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Remove unnecessary `org.IsOrganization()` call Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert to an `int64` keyed `accessMap` * Add type `userAccess` * Add convenience func updateUserAccess() * Turn accessMap into a `map[int64]userAccess` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * or even better: `map[int64]*userAccess` * updateUserAccess(): use tighter syntax as suggested by lafriks * even tighter * Avoid extra loop * Don't disclose limited orgs to unauthenticated users * Don't assume block only applies to orgs * Use an array of `VisibleType` for filtering * fix yet another thinko * Ok - no need for u * Revert "Ok - no need for u" This reverts commit 5c3e886aabd5acd997a3b35687d322439732c200. Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv>
4 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
4 years ago
9 years ago
Add configurable Trust Models (#11712) * Add configurable Trust Models Gitea's default signature verification model differs from GitHub. GitHub uses signatures to verify that the committer is who they say they are - meaning that when GitHub makes a signed commit it must be the committer. The GitHub model prevents re-publishing of commits after revocation of a key and prevents re-signing of other people's commits to create a completely trusted repository signed by one key or a set of trusted keys. The default behaviour of Gitea in contrast is to always display the avatar and information related to a signature. This allows signatures to be decoupled from the committer. That being said, allowing arbitary users to present other peoples commits as theirs is not necessarily desired therefore we have a trust model whereby signatures from collaborators are marked trusted, signatures matching the commit line are marked untrusted and signatures that match a user in the db but not the committer line are marked unmatched. The problem with this model is that this conflicts with Github therefore we need to provide an option to allow users to choose the Github model should they wish to. Signed-off-by: Andrew Thornton <art27@cantab.net> * Adjust locale strings Signed-off-by: Andrew Thornton <art27@cantab.net> * as per @6543 Co-authored-by: 6543 <6543@obermui.de> * Update models/gpg_key.go * Add migration for repository Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
3 years ago
Template Repositories (#8768) * Start work on templates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Continue work Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix IsTemplate vs IsGenerated Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tabs vs spaces * Tabs vs Spaces * Add templates to API & start adding tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix integration tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove unused User Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move template tests to existing repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Minor re-check updates and cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test cleanup Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix optionalbool Signed-off-by: jolheiser <john.olheiser@gmail.com> * make fmt Signed-off-by: jolheiser <john.olheiser@gmail.com> * Test fixes and icon change Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add new user and repo for tests Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests (finally) Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update meta repo with env variables Signed-off-by: jolheiser <john.olheiser@gmail.com> * Move generation to create page Combine with repo create template Modify API search to prioritize owner for repo Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix tests and coverage Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger and JS lint Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix API searching for own private repos Signed-off-by: jolheiser <john.olheiser@gmail.com> * Change wording Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix repo search test. User had a private repo that didn't show up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Another search test fix Signed-off-by: jolheiser <john.olheiser@gmail.com> * Clarify git content Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Feedback updates Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add topics WIP Signed-off-by: jolheiser <john.olheiser@gmail.com> * Finish adding topics Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update locale Signed-off-by: jolheiser <john.olheiser@gmail.com>
4 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package repo
  6. import (
  7. "fmt"
  8. "net/http"
  9. "strings"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/context"
  12. "code.gitea.io/gitea/modules/git"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. api "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/modules/util"
  17. "code.gitea.io/gitea/modules/validation"
  18. "code.gitea.io/gitea/routers/api/v1/utils"
  19. repo_service "code.gitea.io/gitea/services/repository"
  20. )
  21. var searchOrderByMap = map[string]map[string]models.SearchOrderBy{
  22. "asc": {
  23. "alpha": models.SearchOrderByAlphabetically,
  24. "created": models.SearchOrderByOldest,
  25. "updated": models.SearchOrderByLeastUpdated,
  26. "size": models.SearchOrderBySize,
  27. "id": models.SearchOrderByID,
  28. },
  29. "desc": {
  30. "alpha": models.SearchOrderByAlphabeticallyReverse,
  31. "created": models.SearchOrderByNewest,
  32. "updated": models.SearchOrderByRecentUpdated,
  33. "size": models.SearchOrderBySizeReverse,
  34. "id": models.SearchOrderByIDReverse,
  35. },
  36. }
  37. // Search repositories via options
  38. func Search(ctx *context.APIContext) {
  39. // swagger:operation GET /repos/search repository repoSearch
  40. // ---
  41. // summary: Search for repositories
  42. // produces:
  43. // - application/json
  44. // parameters:
  45. // - name: q
  46. // in: query
  47. // description: keyword
  48. // type: string
  49. // - name: topic
  50. // in: query
  51. // description: Limit search to repositories with keyword as topic
  52. // type: boolean
  53. // - name: includeDesc
  54. // in: query
  55. // description: include search of keyword within repository description
  56. // type: boolean
  57. // - name: uid
  58. // in: query
  59. // description: search only for repos that the user with the given id owns or contributes to
  60. // type: integer
  61. // format: int64
  62. // - name: priority_owner_id
  63. // in: query
  64. // description: repo owner to prioritize in the results
  65. // type: integer
  66. // format: int64
  67. // - name: starredBy
  68. // in: query
  69. // description: search only for repos that the user with the given id has starred
  70. // type: integer
  71. // format: int64
  72. // - name: private
  73. // in: query
  74. // description: include private repositories this user has access to (defaults to true)
  75. // type: boolean
  76. // - name: is_private
  77. // in: query
  78. // description: show only pubic, private or all repositories (defaults to all)
  79. // type: boolean
  80. // - name: template
  81. // in: query
  82. // description: include template repositories this user has access to (defaults to true)
  83. // type: boolean
  84. // - name: archived
  85. // in: query
  86. // description: show only archived, non-archived or all repositories (defaults to all)
  87. // type: boolean
  88. // - name: mode
  89. // in: query
  90. // description: type of repository to search for. Supported values are
  91. // "fork", "source", "mirror" and "collaborative"
  92. // type: string
  93. // - name: exclusive
  94. // in: query
  95. // description: if `uid` is given, search only for repos that the user owns
  96. // type: boolean
  97. // - name: sort
  98. // in: query
  99. // description: sort repos by attribute. Supported values are
  100. // "alpha", "created", "updated", "size", and "id".
  101. // Default is "alpha"
  102. // type: string
  103. // - name: order
  104. // in: query
  105. // description: sort order, either "asc" (ascending) or "desc" (descending).
  106. // Default is "asc", ignored if "sort" is not specified.
  107. // type: string
  108. // - name: page
  109. // in: query
  110. // description: page number of results to return (1-based)
  111. // type: integer
  112. // - name: limit
  113. // in: query
  114. // description: page size of results
  115. // type: integer
  116. // responses:
  117. // "200":
  118. // "$ref": "#/responses/SearchResults"
  119. // "422":
  120. // "$ref": "#/responses/validationError"
  121. opts := &models.SearchRepoOptions{
  122. ListOptions: utils.GetListOptions(ctx),
  123. Actor: ctx.User,
  124. Keyword: strings.Trim(ctx.Query("q"), " "),
  125. OwnerID: ctx.QueryInt64("uid"),
  126. PriorityOwnerID: ctx.QueryInt64("priority_owner_id"),
  127. TopicOnly: ctx.QueryBool("topic"),
  128. Collaborate: util.OptionalBoolNone,
  129. Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
  130. Template: util.OptionalBoolNone,
  131. StarredByID: ctx.QueryInt64("starredBy"),
  132. IncludeDescription: ctx.QueryBool("includeDesc"),
  133. }
  134. if ctx.Query("template") != "" {
  135. opts.Template = util.OptionalBoolOf(ctx.QueryBool("template"))
  136. }
  137. if ctx.QueryBool("exclusive") {
  138. opts.Collaborate = util.OptionalBoolFalse
  139. }
  140. var mode = ctx.Query("mode")
  141. switch mode {
  142. case "source":
  143. opts.Fork = util.OptionalBoolFalse
  144. opts.Mirror = util.OptionalBoolFalse
  145. case "fork":
  146. opts.Fork = util.OptionalBoolTrue
  147. case "mirror":
  148. opts.Mirror = util.OptionalBoolTrue
  149. case "collaborative":
  150. opts.Mirror = util.OptionalBoolFalse
  151. opts.Collaborate = util.OptionalBoolTrue
  152. case "":
  153. default:
  154. ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid search mode: \"%s\"", mode))
  155. return
  156. }
  157. if ctx.Query("archived") != "" {
  158. opts.Archived = util.OptionalBoolOf(ctx.QueryBool("archived"))
  159. }
  160. if ctx.Query("is_private") != "" {
  161. opts.IsPrivate = util.OptionalBoolOf(ctx.QueryBool("is_private"))
  162. }
  163. var sortMode = ctx.Query("sort")
  164. if len(sortMode) > 0 {
  165. var sortOrder = ctx.Query("order")
  166. if len(sortOrder) == 0 {
  167. sortOrder = "asc"
  168. }
  169. if searchModeMap, ok := searchOrderByMap[sortOrder]; ok {
  170. if orderBy, ok := searchModeMap[sortMode]; ok {
  171. opts.OrderBy = orderBy
  172. } else {
  173. ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid sort mode: \"%s\"", sortMode))
  174. return
  175. }
  176. } else {
  177. ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid sort order: \"%s\"", sortOrder))
  178. return
  179. }
  180. }
  181. var err error
  182. repos, count, err := models.SearchRepository(opts)
  183. if err != nil {
  184. ctx.JSON(http.StatusInternalServerError, api.SearchError{
  185. OK: false,
  186. Error: err.Error(),
  187. })
  188. return
  189. }
  190. results := make([]*api.Repository, len(repos))
  191. for i, repo := range repos {
  192. if err = repo.GetOwner(); err != nil {
  193. ctx.JSON(http.StatusInternalServerError, api.SearchError{
  194. OK: false,
  195. Error: err.Error(),
  196. })
  197. return
  198. }
  199. accessMode, err := models.AccessLevel(ctx.User, repo)
  200. if err != nil {
  201. ctx.JSON(http.StatusInternalServerError, api.SearchError{
  202. OK: false,
  203. Error: err.Error(),
  204. })
  205. }
  206. results[i] = repo.APIFormat(accessMode)
  207. }
  208. ctx.SetLinkHeader(int(count), opts.PageSize)
  209. ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", count))
  210. ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link")
  211. ctx.JSON(http.StatusOK, api.SearchResults{
  212. OK: true,
  213. Data: results,
  214. })
  215. }
  216. // CreateUserRepo create a repository for a user
  217. func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateRepoOption) {
  218. if opt.AutoInit && opt.Readme == "" {
  219. opt.Readme = "Default"
  220. }
  221. repo, err := repo_service.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
  222. Name: opt.Name,
  223. Description: opt.Description,
  224. IssueLabels: opt.IssueLabels,
  225. Gitignores: opt.Gitignores,
  226. License: opt.License,
  227. Readme: opt.Readme,
  228. IsPrivate: opt.Private,
  229. AutoInit: opt.AutoInit,
  230. DefaultBranch: opt.DefaultBranch,
  231. TrustModel: models.ToTrustModel(opt.TrustModel),
  232. })
  233. if err != nil {
  234. if models.IsErrRepoAlreadyExist(err) {
  235. ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
  236. } else if models.IsErrNameReserved(err) ||
  237. models.IsErrNamePatternNotAllowed(err) {
  238. ctx.Error(http.StatusUnprocessableEntity, "", err)
  239. } else {
  240. ctx.Error(http.StatusInternalServerError, "CreateRepository", err)
  241. }
  242. return
  243. }
  244. // reload repo from db to get a real state after creation
  245. repo, err = models.GetRepositoryByID(repo.ID)
  246. if err != nil {
  247. ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err)
  248. }
  249. ctx.JSON(http.StatusCreated, repo.APIFormat(models.AccessModeOwner))
  250. }
  251. // Create one repository of mine
  252. func Create(ctx *context.APIContext, opt api.CreateRepoOption) {
  253. // swagger:operation POST /user/repos repository user createCurrentUserRepo
  254. // ---
  255. // summary: Create a repository
  256. // consumes:
  257. // - application/json
  258. // produces:
  259. // - application/json
  260. // parameters:
  261. // - name: body
  262. // in: body
  263. // schema:
  264. // "$ref": "#/definitions/CreateRepoOption"
  265. // responses:
  266. // "201":
  267. // "$ref": "#/responses/Repository"
  268. // "409":
  269. // description: The repository with the same name already exists.
  270. // "422":
  271. // "$ref": "#/responses/validationError"
  272. if ctx.User.IsOrganization() {
  273. // Shouldn't reach this condition, but just in case.
  274. ctx.Error(http.StatusUnprocessableEntity, "", "not allowed creating repository for organization")
  275. return
  276. }
  277. CreateUserRepo(ctx, ctx.User, opt)
  278. }
  279. // CreateOrgRepoDeprecated create one repository of the organization
  280. func CreateOrgRepoDeprecated(ctx *context.APIContext, opt api.CreateRepoOption) {
  281. // swagger:operation POST /org/{org}/repos organization createOrgRepoDeprecated
  282. // ---
  283. // summary: Create a repository in an organization
  284. // deprecated: true
  285. // consumes:
  286. // - application/json
  287. // produces:
  288. // - application/json
  289. // parameters:
  290. // - name: org
  291. // in: path
  292. // description: name of organization
  293. // type: string
  294. // required: true
  295. // - name: body
  296. // in: body
  297. // schema:
  298. // "$ref": "#/definitions/CreateRepoOption"
  299. // responses:
  300. // "201":
  301. // "$ref": "#/responses/Repository"
  302. // "422":
  303. // "$ref": "#/responses/validationError"
  304. // "403":
  305. // "$ref": "#/responses/forbidden"
  306. CreateOrgRepo(ctx, opt)
  307. }
  308. // CreateOrgRepo create one repository of the organization
  309. func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) {
  310. // swagger:operation POST /orgs/{org}/repos organization createOrgRepo
  311. // ---
  312. // summary: Create a repository in an organization
  313. // consumes:
  314. // - application/json
  315. // produces:
  316. // - application/json
  317. // parameters:
  318. // - name: org
  319. // in: path
  320. // description: name of organization
  321. // type: string
  322. // required: true
  323. // - name: body
  324. // in: body
  325. // schema:
  326. // "$ref": "#/definitions/CreateRepoOption"
  327. // responses:
  328. // "201":
  329. // "$ref": "#/responses/Repository"
  330. // "404":
  331. // "$ref": "#/responses/notFound"
  332. // "403":
  333. // "$ref": "#/responses/forbidden"
  334. org, err := models.GetOrgByName(ctx.Params(":org"))
  335. if err != nil {
  336. if models.IsErrOrgNotExist(err) {
  337. ctx.Error(http.StatusUnprocessableEntity, "", err)
  338. } else {
  339. ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
  340. }
  341. return
  342. }
  343. if !models.HasOrgVisible(org, ctx.User) {
  344. ctx.NotFound("HasOrgVisible", nil)
  345. return
  346. }
  347. if !ctx.User.IsAdmin {
  348. canCreate, err := org.CanCreateOrgRepo(ctx.User.ID)
  349. if err != nil {
  350. ctx.ServerError("CanCreateOrgRepo", err)
  351. return
  352. } else if !canCreate {
  353. ctx.Error(http.StatusForbidden, "", "Given user is not allowed to create repository in organization.")
  354. return
  355. }
  356. }
  357. CreateUserRepo(ctx, org, opt)
  358. }
  359. // Get one repository
  360. func Get(ctx *context.APIContext) {
  361. // swagger:operation GET /repos/{owner}/{repo} repository repoGet
  362. // ---
  363. // summary: Get a repository
  364. // produces:
  365. // - application/json
  366. // parameters:
  367. // - name: owner
  368. // in: path
  369. // description: owner of the repo
  370. // type: string
  371. // required: true
  372. // - name: repo
  373. // in: path
  374. // description: name of the repo
  375. // type: string
  376. // required: true
  377. // responses:
  378. // "200":
  379. // "$ref": "#/responses/Repository"
  380. ctx.JSON(http.StatusOK, ctx.Repo.Repository.APIFormat(ctx.Repo.AccessMode))
  381. }
  382. // GetByID returns a single Repository
  383. func GetByID(ctx *context.APIContext) {
  384. // swagger:operation GET /repositories/{id} repository repoGetByID
  385. // ---
  386. // summary: Get a repository by id
  387. // produces:
  388. // - application/json
  389. // parameters:
  390. // - name: id
  391. // in: path
  392. // description: id of the repo to get
  393. // type: integer
  394. // format: int64
  395. // required: true
  396. // responses:
  397. // "200":
  398. // "$ref": "#/responses/Repository"
  399. repo, err := models.GetRepositoryByID(ctx.ParamsInt64(":id"))
  400. if err != nil {
  401. if models.IsErrRepoNotExist(err) {
  402. ctx.NotFound()
  403. } else {
  404. ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err)
  405. }
  406. return
  407. }
  408. perm, err := models.GetUserRepoPermission(repo, ctx.User)
  409. if err != nil {
  410. ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
  411. return
  412. } else if !perm.HasAccess() {
  413. ctx.NotFound()
  414. return
  415. }
  416. ctx.JSON(http.StatusOK, repo.APIFormat(perm.AccessMode))
  417. }
  418. // Edit edit repository properties
  419. func Edit(ctx *context.APIContext, opts api.EditRepoOption) {
  420. // swagger:operation PATCH /repos/{owner}/{repo} repository repoEdit
  421. // ---
  422. // summary: Edit a repository's properties. Only fields that are set will be changed.
  423. // produces:
  424. // - application/json
  425. // parameters:
  426. // - name: owner
  427. // in: path
  428. // description: owner of the repo to edit
  429. // type: string
  430. // required: true
  431. // - name: repo
  432. // in: path
  433. // description: name of the repo to edit
  434. // type: string
  435. // required: true
  436. // required: true
  437. // - name: body
  438. // in: body
  439. // description: "Properties of a repo that you can edit"
  440. // schema:
  441. // "$ref": "#/definitions/EditRepoOption"
  442. // responses:
  443. // "200":
  444. // "$ref": "#/responses/Repository"
  445. // "403":
  446. // "$ref": "#/responses/forbidden"
  447. // "422":
  448. // "$ref": "#/responses/validationError"
  449. if err := updateBasicProperties(ctx, opts); err != nil {
  450. return
  451. }
  452. if err := updateRepoUnits(ctx, opts); err != nil {
  453. return
  454. }
  455. if opts.Archived != nil {
  456. if err := updateRepoArchivedState(ctx, opts); err != nil {
  457. return
  458. }
  459. }
  460. ctx.JSON(http.StatusOK, ctx.Repo.Repository.APIFormat(ctx.Repo.AccessMode))
  461. }
  462. // updateBasicProperties updates the basic properties of a repo: Name, Description, Website and Visibility
  463. func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) error {
  464. owner := ctx.Repo.Owner
  465. repo := ctx.Repo.Repository
  466. newRepoName := repo.Name
  467. if opts.Name != nil {
  468. newRepoName = *opts.Name
  469. }
  470. // Check if repository name has been changed and not just a case change
  471. if repo.LowerName != strings.ToLower(newRepoName) {
  472. if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
  473. switch {
  474. case models.IsErrRepoAlreadyExist(err):
  475. ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err)
  476. case models.IsErrNameReserved(err):
  477. ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is reserved [name: %s]", newRepoName), err)
  478. case models.IsErrNamePatternNotAllowed(err):
  479. ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name's pattern is not allowed [name: %s, pattern: %s]", newRepoName, err.(models.ErrNamePatternNotAllowed).Pattern), err)
  480. default:
  481. ctx.Error(http.StatusUnprocessableEntity, "ChangeRepositoryName", err)
  482. }
  483. return err
  484. }
  485. log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
  486. }
  487. // Update the name in the repo object for the response
  488. repo.Name = newRepoName
  489. repo.LowerName = strings.ToLower(newRepoName)
  490. if opts.Description != nil {
  491. repo.Description = *opts.Description
  492. }
  493. if opts.Website != nil {
  494. repo.Website = *opts.Website
  495. }
  496. visibilityChanged := false
  497. if opts.Private != nil {
  498. // Visibility of forked repository is forced sync with base repository.
  499. if repo.IsFork {
  500. *opts.Private = repo.BaseRepo.IsPrivate
  501. }
  502. visibilityChanged = repo.IsPrivate != *opts.Private
  503. // when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
  504. if visibilityChanged && setting.Repository.ForcePrivate && !*opts.Private && !ctx.User.IsAdmin {
  505. err := fmt.Errorf("cannot change private repository to public")
  506. ctx.Error(http.StatusUnprocessableEntity, "Force Private enabled", err)
  507. return err
  508. }
  509. repo.IsPrivate = *opts.Private
  510. }
  511. if opts.Template != nil {
  512. repo.IsTemplate = *opts.Template
  513. }
  514. // Default branch only updated if changed and exist
  515. if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch) {
  516. if err := ctx.Repo.GitRepo.SetDefaultBranch(*opts.DefaultBranch); err != nil {
  517. if !git.IsErrUnsupportedVersion(err) {
  518. ctx.Error(http.StatusInternalServerError, "SetDefaultBranch", err)
  519. return err
  520. }
  521. }
  522. repo.DefaultBranch = *opts.DefaultBranch
  523. }
  524. if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
  525. ctx.Error(http.StatusInternalServerError, "UpdateRepository", err)
  526. return err
  527. }
  528. log.Trace("Repository basic settings updated: %s/%s", owner.Name, repo.Name)
  529. return nil
  530. }
  531. // updateRepoUnits updates repo units: Issue settings, Wiki settings, PR settings
  532. func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
  533. owner := ctx.Repo.Owner
  534. repo := ctx.Repo.Repository
  535. var units []models.RepoUnit
  536. var deleteUnitTypes []models.UnitType
  537. if opts.HasIssues != nil {
  538. if *opts.HasIssues && opts.ExternalTracker != nil && !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
  539. // Check that values are valid
  540. if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
  541. err := fmt.Errorf("External tracker URL not valid")
  542. ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL", err)
  543. return err
  544. }
  545. if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
  546. err := fmt.Errorf("External tracker URL format not valid")
  547. ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL format", err)
  548. return err
  549. }
  550. units = append(units, models.RepoUnit{
  551. RepoID: repo.ID,
  552. Type: models.UnitTypeExternalTracker,
  553. Config: &models.ExternalTrackerConfig{
  554. ExternalTrackerURL: opts.ExternalTracker.ExternalTrackerURL,
  555. ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat,
  556. ExternalTrackerStyle: opts.ExternalTracker.ExternalTrackerStyle,
  557. },
  558. })
  559. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
  560. } else if *opts.HasIssues && opts.ExternalTracker == nil && !models.UnitTypeIssues.UnitGlobalDisabled() {
  561. // Default to built-in tracker
  562. var config *models.IssuesConfig
  563. if opts.InternalTracker != nil {
  564. config = &models.IssuesConfig{
  565. EnableTimetracker: opts.InternalTracker.EnableTimeTracker,
  566. AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime,
  567. EnableDependencies: opts.InternalTracker.EnableIssueDependencies,
  568. }
  569. } else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil {
  570. // Unit type doesn't exist so we make a new config file with default values
  571. config = &models.IssuesConfig{
  572. EnableTimetracker: true,
  573. AllowOnlyContributorsToTrackTime: true,
  574. EnableDependencies: true,
  575. }
  576. } else {
  577. config = unit.IssuesConfig()
  578. }
  579. units = append(units, models.RepoUnit{
  580. RepoID: repo.ID,
  581. Type: models.UnitTypeIssues,
  582. Config: config,
  583. })
  584. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
  585. } else if !*opts.HasIssues {
  586. if !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
  587. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
  588. }
  589. if !models.UnitTypeIssues.UnitGlobalDisabled() {
  590. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
  591. }
  592. }
  593. }
  594. if opts.HasWiki != nil {
  595. if *opts.HasWiki && opts.ExternalWiki != nil && !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
  596. // Check that values are valid
  597. if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
  598. err := fmt.Errorf("External wiki URL not valid")
  599. ctx.Error(http.StatusUnprocessableEntity, "", "Invalid external wiki URL")
  600. return err
  601. }
  602. units = append(units, models.RepoUnit{
  603. RepoID: repo.ID,
  604. Type: models.UnitTypeExternalWiki,
  605. Config: &models.ExternalWikiConfig{
  606. ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL,
  607. },
  608. })
  609. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
  610. } else if *opts.HasWiki && opts.ExternalWiki == nil && !models.UnitTypeWiki.UnitGlobalDisabled() {
  611. config := &models.UnitConfig{}
  612. units = append(units, models.RepoUnit{
  613. RepoID: repo.ID,
  614. Type: models.UnitTypeWiki,
  615. Config: config,
  616. })
  617. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
  618. } else if !*opts.HasWiki {
  619. if !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
  620. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
  621. }
  622. if !models.UnitTypeWiki.UnitGlobalDisabled() {
  623. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
  624. }
  625. }
  626. }
  627. if opts.HasPullRequests != nil {
  628. if *opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() {
  629. // We do allow setting individual PR settings through the API, so
  630. // we get the config settings and then set them
  631. // if those settings were provided in the opts.
  632. unit, err := repo.GetUnit(models.UnitTypePullRequests)
  633. var config *models.PullRequestsConfig
  634. if err != nil {
  635. // Unit type doesn't exist so we make a new config file with default values
  636. config = &models.PullRequestsConfig{
  637. IgnoreWhitespaceConflicts: false,
  638. AllowMerge: true,
  639. AllowRebase: true,
  640. AllowRebaseMerge: true,
  641. AllowSquash: true,
  642. }
  643. } else {
  644. config = unit.PullRequestsConfig()
  645. }
  646. if opts.IgnoreWhitespaceConflicts != nil {
  647. config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
  648. }
  649. if opts.AllowMerge != nil {
  650. config.AllowMerge = *opts.AllowMerge
  651. }
  652. if opts.AllowRebase != nil {
  653. config.AllowRebase = *opts.AllowRebase
  654. }
  655. if opts.AllowRebaseMerge != nil {
  656. config.AllowRebaseMerge = *opts.AllowRebaseMerge
  657. }
  658. if opts.AllowSquash != nil {
  659. config.AllowSquash = *opts.AllowSquash
  660. }
  661. units = append(units, models.RepoUnit{
  662. RepoID: repo.ID,
  663. Type: models.UnitTypePullRequests,
  664. Config: config,
  665. })
  666. } else if !*opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() {
  667. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests)
  668. }
  669. }
  670. if opts.HasProjects != nil && !models.UnitTypeProjects.UnitGlobalDisabled() {
  671. if *opts.HasProjects {
  672. units = append(units, models.RepoUnit{
  673. RepoID: repo.ID,
  674. Type: models.UnitTypeProjects,
  675. })
  676. } else {
  677. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeProjects)
  678. }
  679. }
  680. if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
  681. ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
  682. return err
  683. }
  684. log.Trace("Repository advanced settings updated: %s/%s", owner.Name, repo.Name)
  685. return nil
  686. }
  687. // updateRepoArchivedState updates repo's archive state
  688. func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) error {
  689. repo := ctx.Repo.Repository
  690. // archive / un-archive
  691. if opts.Archived != nil {
  692. if repo.IsMirror {
  693. err := fmt.Errorf("repo is a mirror, cannot archive/un-archive")
  694. ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
  695. return err
  696. }
  697. if *opts.Archived {
  698. if err := repo.SetArchiveRepoState(*opts.Archived); err != nil {
  699. log.Error("Tried to archive a repo: %s", err)
  700. ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
  701. return err
  702. }
  703. log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  704. } else {
  705. if err := repo.SetArchiveRepoState(*opts.Archived); err != nil {
  706. log.Error("Tried to un-archive a repo: %s", err)
  707. ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
  708. return err
  709. }
  710. log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  711. }
  712. }
  713. return nil
  714. }
  715. // Delete one repository
  716. func Delete(ctx *context.APIContext) {
  717. // swagger:operation DELETE /repos/{owner}/{repo} repository repoDelete
  718. // ---
  719. // summary: Delete a repository
  720. // produces:
  721. // - application/json
  722. // parameters:
  723. // - name: owner
  724. // in: path
  725. // description: owner of the repo to delete
  726. // type: string
  727. // required: true
  728. // - name: repo
  729. // in: path
  730. // description: name of the repo to delete
  731. // type: string
  732. // required: true
  733. // responses:
  734. // "204":
  735. // "$ref": "#/responses/empty"
  736. // "403":
  737. // "$ref": "#/responses/forbidden"
  738. owner := ctx.Repo.Owner
  739. repo := ctx.Repo.Repository
  740. canDelete, err := repo.CanUserDelete(ctx.User)
  741. if err != nil {
  742. ctx.Error(http.StatusInternalServerError, "CanUserDelete", err)
  743. return
  744. } else if !canDelete {
  745. ctx.Error(http.StatusForbidden, "", "Given user is not owner of organization.")
  746. return
  747. }
  748. if err := repo_service.DeleteRepository(ctx.User, repo); err != nil {
  749. ctx.Error(http.StatusInternalServerError, "DeleteRepository", err)
  750. return
  751. }
  752. log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name)
  753. ctx.Status(http.StatusNoContent)
  754. }
  755. // GetIssueTemplates returns the issue templates for a repository
  756. func GetIssueTemplates(ctx *context.APIContext) {
  757. // swagger:operation GET /repos/{owner}/{repo}/issue_templates repository repoGetIssueTemplates
  758. // ---
  759. // summary: Get available issue templates for a repository
  760. // produces:
  761. // - application/json
  762. // parameters:
  763. // - name: owner
  764. // in: path
  765. // description: owner of the repo
  766. // type: string
  767. // required: true
  768. // - name: repo
  769. // in: path
  770. // description: name of the repo
  771. // type: string
  772. // required: true
  773. // responses:
  774. // "200":
  775. // "$ref": "#/responses/IssueTemplates"
  776. ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch())
  777. }