diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go
index 12429c88a..aec8c8f81 100644
--- a/integrations/api_repo_test.go
+++ b/integrations/api_repo_test.go
@@ -235,3 +235,53 @@ func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
req := NewRequestf(t, "GET", "/api/v1/repositories/2")
sess.MakeRequest(t, req, http.StatusNotFound)
}
+
+func TestAPIRepoMigrate(t *testing.T) {
+ testCases := []struct {
+ ctxUserID, userID int64
+ cloneURL, repoName string
+ expectedStatus int
+ }{
+ {ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
+ {ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-own", expectedStatus: http.StatusCreated},
+ {ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
+ {ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-org", expectedStatus: http.StatusCreated},
+ {ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
+ }
+
+ prepareTestEnv(t)
+ for _, testCase := range testCases {
+ user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
+ session := loginUser(t, user.Name)
+
+ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate", &api.MigrateRepoOption{
+ CloneAddr: testCase.cloneURL,
+ UID: int(testCase.userID),
+ RepoName: testCase.repoName,
+ })
+ session.MakeRequest(t, req, testCase.expectedStatus)
+ }
+}
+
+func TestAPIOrgRepoCreate(t *testing.T) {
+ testCases := []struct {
+ ctxUserID int64
+ orgName, repoName string
+ expectedStatus int
+ }{
+ {ctxUserID: 1, orgName: "user3", repoName: "repo-admin", expectedStatus: http.StatusCreated},
+ {ctxUserID: 2, orgName: "user3", repoName: "repo-own", expectedStatus: http.StatusCreated},
+ {ctxUserID: 2, orgName: "user6", repoName: "repo-bad-org", expectedStatus: http.StatusForbidden},
+ }
+
+ prepareTestEnv(t)
+ for _, testCase := range testCases {
+ user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
+ session := loginUser(t, user.Name)
+
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", testCase.orgName), &api.CreateRepoOption{
+ Name: testCase.repoName,
+ })
+ session.MakeRequest(t, req, testCase.expectedStatus)
+ }
+}
diff --git a/models/user.go b/models/user.go
index 5ac865879..0b7af8df6 100644
--- a/models/user.go
+++ b/models/user.go
@@ -956,7 +956,7 @@ func deleteUser(e *xorm.Session, u *User) error {
Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil {
return fmt.Errorf("get all watches: %v", err)
}
- if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).Update(new(Repository)); err != nil {
+ if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
return fmt.Errorf("decrease repository num_watches: %v", err)
}
// ***** END: Watch *****
@@ -966,7 +966,7 @@ func deleteUser(e *xorm.Session, u *User) error {
if err = e.Table("star").Cols("star.repo_id").
Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil {
return fmt.Errorf("get all stars: %v", err)
- } else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).Update(new(Repository)); err != nil {
+ } else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
return fmt.Errorf("decrease repository num_stars: %v", err)
}
// ***** END: Star *****
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index dc4ebd405..968fb97a9 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -566,6 +566,11 @@ milestones.due_date=Förfallodatum (valfritt)
milestones.clear=Rensa
milestones.edit=Redigera milstolpe
milestones.cancel=Avbryt
+milestones.modify=Uppdatera milstolpe
+milestones.edit_success=Milstolpe '%s' har blivit uppdaterad.
+milestones.deletion=Ta bort milstolpe
+milestones.deletion_desc=Borttagning av en milstolpe tar bort den från samtliga relaterade ärende. Fortsätta?
+milestones.deletion_success=Milstolpen har blivit borttagen.
milestones.filter_sort.closest_due_date=Närmaste förfallodatum
milestones.filter_sort.furthest_due_date=Mest avlägsna förfallodatum
milestones.filter_sort.least_complete=Minst klar
@@ -573,17 +578,26 @@ milestones.filter_sort.most_complete=Mest klar
milestones.filter_sort.most_issues=Mest ärenden
milestones.filter_sort.least_issues=Minst ärenden
+ext_wiki=Extern Wiki
+ext_wiki.desc=Länk till extern wiki.
wiki=Wiki
+wiki.welcome=Välkommen till Wikin.
+wiki.welcome_desc=Wikin låter dig skriva och dela dokumentation med medarbetare.
+wiki.desc=Skriv och dela dokumentation med medarbetare.
+wiki.create_first_page=Skapa den första sidan
wiki.page=Sida
wiki.filter_page=Filtrera sida
+wiki.new_page=Sida
wiki.default_commit_message=Skriv en anteckning om den här uppdateringen (valfritt).
wiki.save_page=Spara sidan
wiki.last_commit_info=%s redigerade denna sida %s
wiki.edit_page_button=Redigera
wiki.new_page_button=Ny Sida
wiki.delete_page_button=Tag bort sida
+wiki.delete_page_notice_1=Borttagning utav wiki sidan '%s' kan inte ångras. Fortsätta?
wiki.page_already_exists=Wiki-sida med samma namn finns redan.
+wiki.reserved_page=Namnet för wikisidan '%s' är reserverat.
wiki.pages=Sidor
wiki.last_updated=Senast uppdaterad %s
@@ -620,6 +634,9 @@ activity.closed_issue_label=Stängd
activity.new_issues_count_1=Nytt ärende
activity.new_issues_count_n=Nya ärenden
activity.new_issue_label=Öppnad
+activity.title.unresolved_conv_1=%d Olöst konversation
+activity.title.unresolved_conv_n=%d Olösta konversationer
+activity.unresolved_conv_desc=De nyligen förändrade ärendena och pull-requesterna har inte blivit lösta ännu.
activity.unresolved_conv_label=Öppna
activity.title.releases_1=%d release
activity.title.releases_n=%d releaser
@@ -632,6 +649,9 @@ search.results=Sökresultat för ”%s” i %s
settings=Inställningar
settings.desc=Inställningarna är där du kan hantera inställningar för utvecklingskatalogen
+settings.options=Utvecklingskatalog
+settings.collaboration=Medarbetare
+settings.collaboration.admin=Administratör
settings.collaboration.write=Skriva
settings.collaboration.read=Läsa
settings.collaboration.undefined=Odefinierad
@@ -639,10 +659,23 @@ settings.hooks=Webbhookar
settings.githooks=Githookar
settings.basic_settings=Basinställningar
settings.mirror_settings=Inställningar för spegling
+settings.sync_mirror=Synkronisera nu
+settings.mirror_sync_in_progress=Synkronisering utav speglingar pågår. Kontrollera igen om en minut.
+settings.site=Webbplats
settings.update_settings=Uppdatera inställningar
settings.advanced_settings=Advancerade Inställningar
+settings.wiki_desc=Aktivera wiki för utvecklingskatalog
+settings.use_internal_wiki=Använd inbyggd Wiki
+settings.use_external_wiki=Använd extern wiki
settings.external_wiki_url=Extern Wiki-URL
+settings.external_wiki_url_error=Den externa wiki-länken är inte giltig.
+settings.external_wiki_url_desc=Besökare omdirigeras till den externa wiki-länken när de trycker på wiki-tabben.
+settings.issues_desc=Aktivera ärendehantering för utvecklingskatalogen
+settings.use_internal_issue_tracker=Använd inbyggt ärendehanteringssystem
+settings.use_external_issue_tracker=Använd externt ärendehanteringssystem
settings.external_tracker_url=URL För Extern Ärendehanterare
+settings.external_tracker_url_error=Länken för ärendehanteringsystemet är inte en giltig länk.
+settings.external_tracker_url_desc=Besökare dirigeras om till länken för det externa ärendehanteringssystemet när de trycker på ärende-tabben.
settings.tracker_url_format=URL-Format För Extern Ärendehanterare
settings.tracker_issue_style.numeric=Numerisk
settings.tracker_issue_style.alphanumeric=Alfanumerisk
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index 2bd85a3d6..fe93cdf0b 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -492,9 +492,13 @@ owner=Власник
repo_name=Назва репозиторію
repo_name_helper=Хороші назви репозиторіїв використовують короткі, унікальні ключові слова що легко запам'ятати.
visibility=Видимість
+visibility_helper=Створити приватний репозиторій
+visibility_helper_forced=Адміністратор вашого сайту налаштував параметри: всі нові репозиторії будуть приватними.
+visibility_fork_helper=(Ці зміни вплинуть на всі форки.)
clone_helper=Потрібна допомога у клонуванні? Відвідайте сторінку Допомога.
fork_repo=Форкнути репозиторій
fork_from=Форк з
+fork_visibility_helper=Неможливо змінити видимість форкнутого репозиторію.
repo_desc=Опис
repo_lang=Мова
repo_gitignore_helper=Виберіть шаблон .gitignore.
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index ccfe0440c..044b1e9c1 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -257,13 +257,15 @@ func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) {
return
}
- isOwner, err := org.IsOwnedBy(ctx.User.ID)
- if err != nil {
- ctx.ServerError("IsOwnedBy", err)
- return
- } else if !isOwner {
- ctx.Error(403, "", "Given user is not owner of organization.")
- return
+ if !ctx.User.IsAdmin {
+ isOwner, err := org.IsOwnedBy(ctx.User.ID)
+ if err != nil {
+ ctx.ServerError("IsOwnedBy", err)
+ return
+ } else if !isOwner {
+ ctx.Error(403, "", "Given user is not owner of organization.")
+ return
+ }
}
CreateUserRepo(ctx, org, opt)
}
@@ -306,16 +308,23 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
return
}
- if ctxUser.IsOrganization() && !ctx.User.IsAdmin {
- // Check ownership of organization.
- isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID)
- if err != nil {
- ctx.Error(500, "IsOwnedBy", err)
- return
- } else if !isOwner {
- ctx.Error(403, "", "Given user is not owner of organization.")
+ if !ctx.User.IsAdmin {
+ if !ctxUser.IsOrganization() && ctx.User.ID != ctxUser.ID {
+ ctx.Error(403, "", "Given user is not an organization.")
return
}
+
+ if ctxUser.IsOrganization() {
+ // Check ownership of organization.
+ isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID)
+ if err != nil {
+ ctx.Error(500, "IsOwnedBy", err)
+ return
+ } else if !isOwner {
+ ctx.Error(403, "", "Given user is not owner of organization.")
+ return
+ }
+ }
}
remoteAddr, err := form.ParseRemoteAddr(ctx.User)