diff --git a/integrations/pull_update_test.go b/integrations/pull_update_test.go index 484390001..251051582 100644 --- a/integrations/pull_update_test.go +++ b/integrations/pull_update_test.go @@ -58,7 +58,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *models.User) *models.PullReq assert.NoError(t, err) assert.NotEmpty(t, baseRepo) - headRepo, err := repo_module.ForkRepository(actor, forkOrg, baseRepo, "repo-pr-update", "desc") + headRepo, err := repo_module.ForkRepository(actor, forkOrg, baseRepo, "repo-pr-update", "desc", "") assert.NoError(t, err) assert.NotEmpty(t, headRepo) diff --git a/models/action.go b/models/action.go index 003dc1b20..4821910db 100755 --- a/models/action.go +++ b/models/action.go @@ -164,12 +164,24 @@ func (a *Action) GetRepoName() string { return a.Repo.Name } +// GetRepoName returns the name of the action repository. +func (a *Action) GetRepoDisplayName() string { + a.loadRepo() + return a.Repo.DisplayName() +} + // ShortRepoName returns the name of the action repository // trimmed to max 33 chars. func (a *Action) ShortRepoName() string { return base.EllipsisString(a.GetRepoName(), 33) } +// ShortRepoName returns the name of the action repository +// trimmed to max 33 chars. +func (a *Action) ShortRepoDisplayName() string { + return base.EllipsisString(a.GetRepoDisplayName(), 33) +} + // GetRepoPath returns the virtual path to the action repository. func (a *Action) GetRepoPath() string { return path.Join(a.GetRepoUserName(), a.GetRepoName()) @@ -181,6 +193,12 @@ func (a *Action) ShortRepoPath() string { return path.Join(a.ShortRepoUserName(), a.ShortRepoName()) } +// ShortRepoPath returns the virtual path to the action repository +// trimmed to max 20 + 1 + 33 chars. +func (a *Action) ShortRepoFullDisplayName() string { + return path.Join(a.ShortRepoUserName(), a.ShortRepoDisplayName()) +} + // GetRepoLink returns relative link to action repository. func (a *Action) GetRepoLink() string { if len(setting.AppSubURL) > 0 { diff --git a/models/repo.go b/models/repo.go index f393b51b2..027ced6ff 100755 --- a/models/repo.go +++ b/models/repo.go @@ -12,6 +12,7 @@ import ( "errors" "fmt" "html/template" + "math/rand" "xorm.io/xorm" "code.gitea.io/gitea/modules/blockchain" @@ -221,8 +222,10 @@ type Repository struct { CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` - Hot int64 `xorm:"-"` - Active int64 `xorm:"-"` + Hot int64 `xorm:"-"` + Active int64 `xorm:"-"` + Alias string `xorm:"INDEX"` + LowerAlias string `xorm:"INDEX"` } // SanitizedOriginalURL returns a sanitized OriginalURL @@ -233,6 +236,14 @@ func (repo *Repository) SanitizedOriginalURL() string { return util.SanitizeURLCredentials(repo.OriginalURL, false) } +// GetAlias returns a sanitized OriginalURL +func (repo *Repository) DisplayName() string { + if repo.Alias == "" { + return repo.Name + } + return repo.Alias +} + // ColorFormat returns a colored string to represent this repo func (repo *Repository) ColorFormat(s fmt.State) { var ownerName interface{} @@ -286,6 +297,11 @@ func (repo *Repository) FullName() string { return repo.OwnerName + "/" + repo.Name } +// FullDisplayName returns the repository full display name +func (repo *Repository) FullDisplayName() string { + return repo.OwnerName + "/" + repo.DisplayName() +} + // HTMLURL returns the repository HTML URL func (repo *Repository) HTMLURL() string { return setting.AppURL + repo.FullName() @@ -385,7 +401,9 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) ID: repo.ID, Owner: repo.Owner.APIFormat(), Name: repo.Name, + Alias: repo.Alias, FullName: repo.FullName(), + FullDisplayName: repo.FullDisplayName(), Description: repo.Description, Private: repo.IsPrivate, Template: repo.IsTemplate, @@ -921,17 +939,50 @@ func (repo *Repository) DescriptionHTML() template.HTML { return template.HTML(markup.Sanitize(string(desc))) } -func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) { - has, err := e.Get(&Repository{ - OwnerID: u.ID, - LowerName: strings.ToLower(repoName), - }) - return has && com.IsDir(RepoPath(u.Name, repoName)), err +func isRepositoryExist(e Engine, u *User, repoName string, alias string) (bool, error) { + var cond = builder.NewCond() + cond = cond.And(builder.Eq{"owner_id": u.ID}) + if alias != "" { + subCon := builder.NewCond() + subCon = subCon.Or(builder.Eq{"lower_alias": strings.ToLower(alias)}, builder.Eq{"lower_name": strings.ToLower(repoName)}) + cond = cond.And(subCon) + } else { + cond = cond.And(builder.Eq{"lower_name": strings.ToLower(repoName)}) + } + count, err := e.Where(cond).Count(&Repository{}) + return count > 0 || com.IsDir(RepoPath(u.Name, repoName)), err } // IsRepositoryExist returns true if the repository with given name under user has already existed. -func IsRepositoryExist(u *User, repoName string) (bool, error) { - return isRepositoryExist(x, u, repoName) +func IsRepositoryExist(u *User, repoName string, alias string) (bool, error) { + return isRepositoryExist(x, u, repoName, alias) +} + +// IsRepositoryAliasExist returns true if the repository with given alias under user has already existed. +func IsRepositoryAliasExist(u *User, alias string) (bool, error) { + return isRepositoryAliasExist(x, u, alias) +} + +func isRepositoryAliasExist(e Engine, u *User, alias string) (bool, error) { + var cond = builder.NewCond() + cond = cond.And(builder.Eq{"owner_id": u.ID}) + cond = cond.And(builder.Eq{"lower_alias": strings.ToLower(alias)}) + count, err := e.Where(cond).Count(&Repository{}) + return count > 0, err +} + +func IsRepositoryAliasAvailable(doer *User, alias string) error { + if err := IsUsableRepoAlias(alias); err != nil { + return err + } + + has, err := IsRepositoryAliasExist(doer, alias) + if err != nil { + return fmt.Errorf("IsRepositoryExist: %v", err) + } else if has { + return ErrRepoAlreadyExist{doer.Name, alias} + } + return nil } // CloneLink represents different types of clone URLs of repository. @@ -975,20 +1026,24 @@ func (repo *Repository) CloneLink() (cl *CloneLink) { } // CheckCreateRepository check if could created a repository -func CheckCreateRepository(doer, u *User, name string) error { +func CheckCreateRepository(doer, u *User, repoName, alias string) error { if !doer.CanCreateRepo() { return ErrReachLimitOfRepo{u.MaxRepoCreation} } - if err := IsUsableRepoName(name); err != nil { + if err := IsUsableRepoName(repoName); err != nil { return err } - has, err := isRepositoryExist(x, u, name) + if err := IsUsableRepoAlias(alias); err != nil { + return err + } + + has, err := isRepositoryExist(x, u, repoName, alias) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { - return ErrRepoAlreadyExist{u.Name, name} + return ErrRepoAlreadyExist{u.Name, repoName} } return nil } @@ -996,6 +1051,7 @@ func CheckCreateRepository(doer, u *User, name string) error { // CreateRepoOptions contains the create repository options type CreateRepoOptions struct { Name string + Alias string Description string OriginalURL string GitServiceType api.GitServiceType @@ -1036,8 +1092,10 @@ func GetRepoInitFile(tp, name string) ([]byte, error) { } var ( - reservedRepoNames = []string{".", ".."} - reservedRepoPatterns = []string{"*.git", "*.wiki"} + reservedRepoNames = []string{".", ".."} + reservedRepoPatterns = []string{"*.git", "*.wiki"} + reservedRepoAliasNames = []string{} + reservedRepoAliasPatterns = []string{} ) // IsUsableRepoName returns true when repository is usable @@ -1045,13 +1103,22 @@ func IsUsableRepoName(name string) error { return isUsableName(reservedRepoNames, reservedRepoPatterns, name) } +// IsUsableRepoAlias returns true when repository alias is usable +func IsUsableRepoAlias(name string) error { + return isUsableName(reservedRepoAliasNames, reservedRepoAliasPatterns, name) +} + // CreateRepository creates a repository for the user/organization. func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error) { + repo.LowerAlias = strings.ToLower(repo.Alias) if err = IsUsableRepoName(repo.Name); err != nil { return err } - has, err := isRepositoryExist(ctx.e, u, repo.Name) + if err := IsUsableRepoAlias(repo.Alias); err != nil { + return err + } + has, err := isRepositoryExist(ctx.e, u, repo.Name, repo.Alias) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -1233,7 +1300,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } // Check if new owner has repository with same name. - has, err := IsRepositoryExist(newOwner, repo.Name) + has, err := IsRepositoryExist(newOwner, repo.Name, repo.Alias) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -1366,7 +1433,7 @@ func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err return err } - has, err := IsRepositoryExist(repo.Owner, newRepoName) + has, err := IsRepositoryExist(repo.Owner, newRepoName, "") if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -1848,6 +1915,26 @@ func getRepositoryByOwnerAndName(e Engine, ownerName, repoName string) (*Reposit return &repo, nil } +// GetRepositoryByOwnerAndAlias returns the repository by given ownername and reponame. +func GetRepositoryByOwnerAndAlias(ownerName, alias string) (*Repository, error) { + return getRepositoryByOwnerAndAlias(x, ownerName, alias) +} + +func getRepositoryByOwnerAndAlias(e Engine, ownerName, alias string) (*Repository, error) { + var repo Repository + has, err := e.Table("repository").Select("repository.*"). + Join("INNER", "`user`", "`user`.id = repository.owner_id"). + Where("repository.lower_alias = ?", strings.ToLower(alias)). + And("`user`.lower_name = ?", strings.ToLower(ownerName)). + Get(&repo) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRepoNotExist{0, 0, ownerName, alias} + } + return &repo, nil +} + // GetRepositoryByName returns the repository by given name under user if exists. func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { repo := &Repository{ @@ -2521,6 +2608,14 @@ func UpdateRepositoryCommitNum(repo *Repository) error { return nil } +func GenerateDefaultRepoName(ownerName string) string { + if len(ownerName) > 5 { + ownerName = ownerName[:5] + } + now := time.Now().Format("20060102150405") + return ownerName + now + fmt.Sprint(rand.Intn(10)) +} + type RepoFile struct { CommitId string Content []byte diff --git a/models/repo_generate.go b/models/repo_generate.go index 480683cd4..08bb1463d 100644 --- a/models/repo_generate.go +++ b/models/repo_generate.go @@ -19,6 +19,7 @@ import ( // GenerateRepoOptions contains the template units to generate type GenerateRepoOptions struct { Name string + Alias string Description string Private bool GitContent bool diff --git a/models/repo_list.go b/models/repo_list.go index c4d8ee823..e41b0f49d 100755 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -200,8 +200,8 @@ const ( SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" - SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" - SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" + SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" + SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" ) // SearchRepositoryCondition creates a query condition according search repository options @@ -321,6 +321,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { var likes = builder.NewCond() for _, v := range strings.Split(opts.Keyword, ",") { likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) + likes = likes.Or(builder.Like{"alias", v}) if opts.IncludeDescription { likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) } diff --git a/models/repo_tag.go b/models/repo_tag.go index 76740bd76..984f9e2db 100644 --- a/models/repo_tag.go +++ b/models/repo_tag.go @@ -28,6 +28,7 @@ type OfficialTagRepos struct { type TagReposBrief struct { RepoID int64 RepoName string + Alias string TagID int64 } @@ -97,7 +98,7 @@ func UpdateTagReposByID(tagID, orgID int64, repoIdList []int64) error { func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) { t := make([]TagReposBrief, 0) - const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc" + const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t1.alias,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc" if err := x.SQL(SQLCmd, tagID, orgID).Find(&t); err != nil { return nil, err @@ -108,9 +109,13 @@ func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) { if v.TagID > 0 { selected = true } + repoName := v.Alias + if v.Alias == "" { + repoName = v.RepoName + } r = append(r, TagReposSelected{ RepoID: v.RepoID, - RepoName: v.RepoName, + RepoName: repoName, Selected: selected, }) } diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 352e50ca0..6a156491d 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -186,6 +186,8 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field)) case validation.ErrGlobPattern: data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message) + case validation.ErrAlphaDashDotChinese: + data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_chinese_error") default: data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification } diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 8061c6469..32890a5c1 100755 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -29,6 +29,7 @@ import ( type CreateRepoForm struct { UID int64 `binding:"Required"` RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"` + Alias string `binding:"Required;MaxSize(100);AlphaDashDotChinese"` Private bool Description string `binding:"MaxSize(1024)"` DefaultBranch string `binding:"GitRefName;MaxSize(100)"` @@ -62,6 +63,7 @@ type MigrateRepoForm struct { UID int64 `json:"uid" binding:"Required"` // required: true RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"` + Alias string `json:"alias" binding:"Required;AlphaDashDotChinese;MaxSize(100)"` Mirror bool `json:"mirror"` Private bool `json:"private"` Description string `json:"description" binding:"MaxSize(255)"` @@ -109,6 +111,7 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) { // RepoSettingForm form for changing repository settings type RepoSettingForm struct { RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"` + Alias string `binding:"Required;AlphaDashDotChinese;MaxSize(100)"` Description string `binding:"MaxSize(255)"` Website string `binding:"ValidUrl;MaxSize(255)"` Interval string diff --git a/modules/notification/action/action.go b/modules/notification/action/action.go index 9956940f3..4bc296657 100644 --- a/modules/notification/action/action.go +++ b/modules/notification/action/action.go @@ -154,6 +154,22 @@ func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models. } } +func (a *actionNotifier) NotifyAliasRepository(doer *models.User, repo *models.Repository, oldAlias string) { + log.Trace("action.ChangeRepositoryAlias: %s/%s", doer.Name, repo.Alias) + + if err := models.NotifyWatchers(&models.Action{ + ActUserID: doer.ID, + ActUser: doer, + OpType: models.ActionRenameRepo, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, + Content: oldAlias, + }); err != nil { + log.Error("NotifyWatchers: %v", err) + } +} + func (a *actionNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) { if err := models.NotifyWatchers(&models.Action{ ActUserID: doer.ID, diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 0b3e1173b..8325f710c 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -18,6 +18,7 @@ type Notifier interface { NotifyDeleteRepository(doer *models.User, repo *models.Repository) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) + NotifyAliasRepository(doer *models.User, repo *models.Repository, oldAlias string) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) NotifyNewIssue(*models.Issue) diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index d2fd51d71..a74c47980 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -135,6 +135,10 @@ func (*NullNotifier) NotifyDeleteRef(doer *models.User, repo *models.Repository, func (*NullNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string) { } +func (a *NullNotifier) NotifyAliasRepository(doer *models.User, repo *models.Repository, oldAlias string) { + +} + // NotifyTransferRepository places a place holder function func (*NullNotifier) NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string) { } diff --git a/modules/repository/create.go b/modules/repository/create.go index d740c58b1..f5dfa63d6 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -28,6 +28,7 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *m Owner: u, OwnerName: u.Name, Name: opts.Name, + Alias: opts.Alias, LowerName: strings.ToLower(opts.Name), Description: opts.Description, OriginalURL: opts.OriginalURL, diff --git a/modules/repository/fork.go b/modules/repository/fork.go index 2ed2a0eb7..da9039d00 100644 --- a/modules/repository/fork.go +++ b/modules/repository/fork.go @@ -15,7 +15,7 @@ import ( ) // ForkRepository forks a repository -func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name, desc string) (_ *models.Repository, err error) { +func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name, desc, alias string) (_ *models.Repository, err error) { forkedRepo, err := oldRepo.GetUserFork(owner.ID) if err != nil { return nil, err @@ -33,6 +33,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name, Owner: owner, OwnerName: owner.Name, Name: name, + Alias: alias, LowerName: strings.ToLower(name), Description: desc, DefaultBranch: oldRepo.DefaultBranch, diff --git a/modules/repository/fork_test.go b/modules/repository/fork_test.go index cb3526bcc..f599ead68 100644 --- a/modules/repository/fork_test.go +++ b/modules/repository/fork_test.go @@ -18,7 +18,7 @@ func TestForkRepository(t *testing.T) { user := models.AssertExistsAndLoadBean(t, &models.User{ID: 13}).(*models.User) repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository) - fork, err := ForkRepository(user, user, repo, "test", "test") + fork, err := ForkRepository(user, user, repo, "test", "test", "test") assert.Nil(t, fork) assert.Error(t, err) assert.True(t, models.IsErrForkAlreadyExist(err)) diff --git a/modules/repository/generate.go b/modules/repository/generate.go index 6d80488de..86c9a5c28 100644 --- a/modules/repository/generate.go +++ b/modules/repository/generate.go @@ -236,6 +236,7 @@ func GenerateRepository(ctx models.DBContext, doer, owner *models.User, template Owner: owner, OwnerName: owner.Name, Name: opts.Name, + Alias: opts.Alias, LowerName: strings.ToLower(opts.Name), Description: opts.Description, IsPrivate: opts.Private, diff --git a/modules/repository/init.go b/modules/repository/init.go index 3d1c663c8..5dc352d65 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -51,7 +51,7 @@ func prepareRepoCommit(ctx models.DBContext, repo *models.Repository, tmpDir, re cloneLink := repo.CloneLink() match := map[string]string{ - "Name": repo.Name, + "Name": repo.DisplayName(), "Description": repo.Description, "CloneURL.SSH": cloneLink.SSH, "CloneURL.HTTPS": cloneLink.HTTPS, diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 70de9b746..e290488a4 100755 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -46,31 +46,33 @@ type ExternalWiki struct { // Repository represents a repository type Repository struct { - ID int64 `json:"id"` - Owner *User `json:"owner"` - Name string `json:"name"` - FullName string `json:"full_name"` - Description string `json:"description"` - Empty bool `json:"empty"` - Private bool `json:"private"` - Fork bool `json:"fork"` - Template bool `json:"template"` - Parent *Repository `json:"parent"` - Mirror bool `json:"mirror"` - Size int `json:"size"` - HTMLURL string `json:"html_url"` - SSHURL string `json:"ssh_url"` - CloneURL string `json:"clone_url"` - OriginalURL string `json:"original_url"` - Website string `json:"website"` - Stars int `json:"stars_count"` - Forks int `json:"forks_count"` - Watchers int `json:"watchers_count"` - OpenIssues int `json:"open_issues_count"` - OpenPulls int `json:"open_pr_counter"` - Releases int `json:"release_counter"` - DefaultBranch string `json:"default_branch"` - Archived bool `json:"archived"` + ID int64 `json:"id"` + Owner *User `json:"owner"` + Name string `json:"name"` + Alias string `json:"alias"` + FullName string `json:"full_name"` + FullDisplayName string `json:"full_display_name"` + Description string `json:"description"` + Empty bool `json:"empty"` + Private bool `json:"private"` + Fork bool `json:"fork"` + Template bool `json:"template"` + Parent *Repository `json:"parent"` + Mirror bool `json:"mirror"` + Size int `json:"size"` + HTMLURL string `json:"html_url"` + SSHURL string `json:"ssh_url"` + CloneURL string `json:"clone_url"` + OriginalURL string `json:"original_url"` + Website string `json:"website"` + Stars int `json:"stars_count"` + Forks int `json:"forks_count"` + Watchers int `json:"watchers_count"` + OpenIssues int `json:"open_issues_count"` + OpenPulls int `json:"open_pr_counter"` + Releases int `json:"release_counter"` + DefaultBranch string `json:"default_branch"` + Archived bool `json:"archived"` // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time @@ -217,6 +219,7 @@ type MigrateRepoOption struct { UID int `json:"uid" binding:"Required"` // required: true RepoName string `json:"repo_name" binding:"Required"` + Alias string `json:"alias" binding:"Required"` Mirror bool `json:"mirror"` Private bool `json:"private"` Description string `json:"description"` diff --git a/modules/task/task.go b/modules/task/task.go index 72f111ecc..722e39bec 100644 --- a/modules/task/task.go +++ b/modules/task/task.go @@ -84,6 +84,7 @@ func CreateMigrateTask(doer, u *models.User, opts base.MigrateOptions) (*models. repo, err := repo_module.CreateRepository(doer, u, models.CreateRepoOptions{ Name: opts.RepoName, + Alias: opts.Alias, Description: opts.Description, OriginalURL: opts.OriginalURL, GitServiceType: opts.GitServiceType, diff --git a/modules/validation/binding.go b/modules/validation/binding.go index 1c67878ea..b608cdea2 100644 --- a/modules/validation/binding.go +++ b/modules/validation/binding.go @@ -19,6 +19,8 @@ const ( // ErrGlobPattern is returned when glob pattern is invalid ErrGlobPattern = "GlobPattern" + + ErrAlphaDashDotChinese = "AlphaDashDotChineseError" ) var ( @@ -26,6 +28,8 @@ var ( // They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere. // They cannot have question-mark ?, asterisk *, or open bracket [ anywhere GitRefNamePatternInvalid = regexp.MustCompile(`[\000-\037\177 \\~^:?*[]+`) + + AlphaDashDotChinese = regexp.MustCompile("^[\u4e00-\u9fa5\\.\\-_A-Za-z0-9]+$") ) // CheckGitRefAdditionalRulesValid check name is valid on additional rules @@ -53,6 +57,7 @@ func AddBindingRules() { addGitRefNameBindingRule() addValidURLBindingRule() addGlobPatternRule() + addAlphaDashDotChineseRule() } func addGitRefNameBindingRule() { @@ -117,6 +122,21 @@ func addGlobPatternRule() { }) } +func addAlphaDashDotChineseRule() { + binding.AddRule(&binding.Rule{ + IsMatch: func(rule string) bool { + return strings.HasPrefix(rule, "AlphaDashDotChinese") + }, + IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) { + if !ValidAlphaDashDotChinese(fmt.Sprintf("%v", val)) { + errs.Add([]string{name}, ErrAlphaDashDotChinese, "ErrAlphaDashDotChinese") + return false, errs + } + return true, errs + }, + }) +} + func portOnly(hostport string) string { colon := strings.IndexByte(hostport, ':') if colon == -1 { @@ -139,3 +159,7 @@ func validPort(p string) bool { } return true } + +func ValidAlphaDashDotChinese(value string) bool { + return AlphaDashDotChinese.MatchString(value) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 739d515bc..68cf292e2 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -348,7 +348,9 @@ modify = Update [form] UserName = Username -RepoName = Repository name +Alias = Repository name +RepoPath = Repository path +RepoAdress = Repository Adress Email = Email address Password = Password Retype = Re-Type Password @@ -372,7 +374,10 @@ SSPIDefaultLanguage = Default Language require_error = ` cannot be empty.` alpha_dash_error = ` should contain only alphanumeric, dash ('-') and underscore ('_') characters.` alpha_dash_dot_error = ` should contain only alphanumeric, dash ('-'), underscore ('_') and dot ('.') characters.` +reponame_dash_dot_error=` Please enter Chinese, alphanumeric, dash ('-') ,underscore ('_') and dot ('.')characters, up to 100 characters. ` +repoadd_dash_dot_error=` Path only allows input alphanumeric, dash ('-') ,underscore ('_') and dot ('.')characters, up to 100 characters. ` git_ref_name_error = ` must be a well-formed Git reference name.` +alpha_dash_dot_chinese_error= ` should contain only alphanumeric, chinese, dash ('-') and underscore ('_') characters.` size_error = ` must be size %s.` min_size_error = ` must contain at least %s characters.` max_size_error = ` must contain at most %s characters.` @@ -386,7 +391,7 @@ password_not_match = The passwords do not match. lang_select_error = Select a language from the list. username_been_taken = The username is already taken. -repo_name_been_taken = The repository name is already used. +repo_name_been_taken = The repository name or path is already used. visit_rate_limit = Remote visit addressed rate limitation. 2fa_auth_required = Remote visit required two factors authentication. org_name_been_taken = The organization name is already taken. @@ -899,7 +904,7 @@ modelarts.train_job.description=Description modelarts.train_job.parameter_setting=Parameter setting modelarts.train_job.parameter_setting_info=Parameter Info modelarts.train_job.fast_parameter_setting=fast_parameter_setting -modelarts.train_job.fast_parameter_setting_config=fast_parameter_setting_config +modelarts.train_job.fast_parameter_setting_config=fast_parameter_setting_config modelarts.train_job.fast_parameter_setting_config_link=fast_parameter_setting_config_link modelarts.train_job.frames=frames modelarts.train_job.algorithm_origin=Algorithm Origin @@ -974,6 +979,9 @@ template.avatar = Avatar template.issue_labels = Issue Labels template.one_item = Must select at least one template item template.invalid = Must select a template repository +template.repo_adress=Adress +template.repo_path=path +template.repo_name=Name archive.title = This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests. archive.issue.nocomment = This repo is archived. You cannot comment on issues. @@ -1194,7 +1202,7 @@ issues.filter_label_exclude = `Use alt + click/enter t issues.filter_label_no_select = All labels issues.filter_milestone = Milestone issues.filter_milestone_no_select = All milestones -issues.filter_milestone_no_add = Not add milestones +issues.filter_milestone_no_add = Not add milestones issues.filter_assignee = Assignee issues.filter_assginee_no_select = All assignees issues.filter_type = Type diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 935b6112b..7f8bab699 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -350,7 +350,10 @@ modify=更新 [form] UserName=用户名 -RepoName=项目名称 +RepoName=项目路径 +Alias=项目名称 +RepoPath=项目路径 +RepoAdress=项目地址 Email=邮箱地址 Password=密码 Retype=重新输入密码 @@ -374,7 +377,10 @@ SSPIDefaultLanguage=默认语言 require_error=不能为空。 alpha_dash_error=应该只包含字母数字、破折号 ('-') 和下划线 ('_') 字符。 alpha_dash_dot_error=应该只包含字母数字, 破折号 ('-'), 下划线 ('_') 和点 ('. ') 。 +reponame_dash_dot_error=请输入中文、字母、数字和-_ .,最多100个字符。 +repoadd_dash_dot_error=路径只允许字母、数字和-_ .,最多100个字符。 git_ref_name_error=` 必须是格式良好的 git 引用名称。` +alpha_dash_dot_chinese_error=应该只包含字母数字中文, 破折号 ('-'), 下划线 ('_') 和点 ('. ') 。 size_error=长度必须为 %s。 min_size_error=长度最小为 %s 个字符。 max_size_error=长度最大为 %s 个字符。 @@ -388,7 +394,7 @@ password_not_match=密码不匹配。 lang_select_error=从列表中选出语言 username_been_taken=用户名已被使用。 -repo_name_been_taken=项目名称已被使用。 +repo_name_been_taken=项目名称或项目路径已被使用。 visit_rate_limit=远程访问达到速度限制。 2fa_auth_required=远程访问需要双重验证。 org_name_been_taken=组织名称已被使用。 @@ -984,6 +990,9 @@ template.avatar=头像 template.issue_labels=任务标签 template.one_item=必须至少选择一个模板项 template.invalid=必须选择一个模板项目 +template.repo_adress=项目地址 +template.repo_path=项目地址 +template.repo_name=项目名称 archive.title=此项目已存档。您可以查看文件和克隆,但不能推送或创建任务/合并请求。 archive.issue.nocomment=此项目已存档,您不能在此任务添加评论。 diff --git a/public/home/home.js b/public/home/home.js index d7eb5ab04..f49c8248b 100644 --- a/public/home/home.js +++ b/public/home/home.js @@ -4,7 +4,6 @@ if(isEmpty(token)){ var meta = $("meta[name=_uid]"); if(!isEmpty(meta)){ token = meta.attr("content"); - console.log("token is uid:" + token); } } @@ -33,8 +32,6 @@ var swiperRepo = new Swiper(".homepro-list", { }); var output = document.getElementById("newmessage"); -console.log("document.location.host="+document.location.host); -console.log("document.URL="+document.URL); var url = "ws://" + document.location.host + "/action/notification"; if(document.location.host == "git.openi.org.cn" || document.URL.startsWith("https")){ url = "wss://" + document.location.host + "/action/notification" @@ -51,18 +48,14 @@ var html =document.documentElement; var lang = html.attributes["lang"] var isZh = true; if(lang != null && lang.nodeValue =="en-US" ){ - console.log("the language is " + lang.nodeValue); isZh=false; }else{ - console.log("default lang=zh"); } socket.onmessage = function (e) { var data =JSON.parse(e.data) - console.log("recevie data=" + e.data) var html = ""; if (data != null){ - console.log("queue length=" + messageQueue.length); if(messageQueue.length > maxSize){ delete messageQueue[0]; }else{ @@ -71,38 +64,38 @@ socket.onmessage = function (e) { var currentTime = new Date().getTime(); for(var i = 0; i < messageQueue.length; i++){ var record = messageQueue[i]; - + var recordPrefix = getMsg(record); var actionName = getAction(record.OpType,isZh); - + if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){ html += recordPrefix + actionName; - html += " " + getIssueText(record) + "" + html += " " + getIssueText(record) + "" } else if(record.OpType == "7" || record.OpType == "11" || record.OpType == "14" || record.OpType == "15" || record.OpType == "22" || record.OpType == "23"){ html += recordPrefix + actionName; - html += " " + getPRText(record) + "" + html += " " + getPRText(record) + "" } else if(record.OpType == "1"){ html += recordPrefix + actionName; - html += " " + getRepoLink(record) + "" + html += " " +getRepotext(record) + "" } else if(record.OpType == "9" || record.OpType == "5"){ branch = "" + record.RefName + "" actionName = actionName.replace("{branch}",branch); html += recordPrefix + actionName; - html += " " + getRepoLink(record) + "" + html += " " + getRepotext(record) + "" }else if(record.OpType == "17"){ actionName = actionName.replace("{deleteBranchName}",record.RefName); - var repoLink = "" + getRepoLink(record) + "" + var repoLink = "" + getRepotext(record) + "" actionName = actionName.replace("{repoName}",repoLink); html += recordPrefix + actionName; } else if(record.OpType == "2"){ actionName = actionName.replace("{oldRepoName}",record.Content); html += recordPrefix + actionName; - html += " " + getRepoLink(record) + "" + html += " " + getRepotext(record) + "" } else{ continue; @@ -115,17 +108,8 @@ socket.onmessage = function (e) { html += ""; html += ""; } - /* -
- -
- zhoupzh 合并了合并请求 OpenI/aiforge#116822 分钟前 -
-
- */ } - console.log("html=" + html) output.innerHTML = html; swiperNewMessage.updateSlides(); swiperNewMessage.updateProgress(); @@ -136,15 +120,20 @@ function getMsg(record){ html += "
"; html += " \"\"" html += "
" - html += " " + record.ActUser.Name + "" + html += " " + record.ActUser.Name + "" return html; } -function getRepoLink(record){ - return "/" + record.Repo.OwnerName + "/" + record.Repo.Name; +function getRepotext(record){ + if(record.Repo.Alias){ + return record.Repo.OwnerName + "/" + record.Repo.Alias; + }else{ + return record.Repo.OwnerName + "/" + record.Repo.Name; + } } function getRepoLink(record){ return record.Repo.OwnerName + "/" + record.Repo.Name; + } function getTime(UpdatedUnix,currentTime){ @@ -154,8 +143,7 @@ function getTime(UpdatedUnix,currentTime){ if( timeEscSecond < 0){ timeEscSecond = 1; } - console.log("currentTime=" + currentTime + " updateUnix=" + UpdatedUnix); - + var hours= Math.floor(timeEscSecond / 3600); //计算相差分钟数 var leave2 = Math.floor(timeEscSecond % (3600)); //计算小时数后剩余的秒数 @@ -179,11 +167,16 @@ function getPRLink(record){ return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/pulls/" + getIssueId(record); } function getPRText(record){ - return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record); + if(record.Repo.Alias){ + return record.Repo.OwnerName + "/" + record.Repo.Alias + "#" + getIssueId(record); + }else{ + return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record); + } + } function getIssueLink(record){ - + return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/issues/" + getIssueId(record); } @@ -204,7 +197,12 @@ function getIssueId(record){ } function getIssueText(record){ - return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record); + if(record.Repo.Alias){ + return record.Repo.OwnerName + "/" + record.Repo.Alias + "#" + getIssueId(record); + }else{ + return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record); + } + } /* @@ -289,7 +287,7 @@ var repoAndOrgEN={ "2":"Member ", "3":"Team", "11":"Repositories", - "22":"Members ", + "21":"Members ", "31":"Teams", "4":" hour ago", "5":" minute ago", @@ -320,11 +318,9 @@ function queryRecommendData(){ dataType:"json", async:false, success:function(json){ - console.log(json); displayOrg(json); }, error:function(response) { - console.log(response); } }); @@ -337,40 +333,14 @@ function queryRecommendData(){ dataType:"json", async:false, success:function(json){ - console.log(json); displayRepo(json); }, error:function(response) { - console.log(response); } }); } -/* -
-
-
- - 276 32 - - - aiforge - -
- 本项目是群体化方法与技术的开源实现案例,在基于Gitea的基础上,进一步支持社交化的协同开发、协同学习、协同研究等群体创新实践服务,特别是针对新一代人工智能技术特点,重点支持项目管理、git代码管理、大数据集存储管理与智能计算平台接入。 -
- -
-
-
-*/ function displayRepo(json){ var orgRepo = document.getElementById("recommendrepo"); var html = ""; @@ -384,7 +354,7 @@ function displayRepo(json){ html += " " + record["NumStars"] + "" + record["NumForks"]; html += " "; html += " "; - html += " " + record["Name"] +""; + html += " " + record["Alias"] +""; html += "
" + record["Description"] + "
"; html += "
" if(record["Topics"] != null){ @@ -405,27 +375,6 @@ function displayRepo(json){ swiperRepo.updateProgress(); } -/** - * - *
-
-
-
- -
- OpenI 启智社区 -
39 项目 ・ 60 成员 ・ 23 团队
-
-
-
-
-
- - */ - -//var repoAndOrgZH = new Map([['1', "项目"], ['2', "成员"], ['3', "团队"]]); -//var repoAndOrgEN = new Map([['1', "Repository"], ['2', "Members"], ['3', "Teams"]]); - function getRepoOrOrg(key,isZhLang,numbers=1){ if(numbers > 1){ @@ -437,7 +386,6 @@ function getRepoOrOrg(key,isZhLang,numbers=1){ return repoAndOrgEN[key]; } } - function displayOrg(json){ var orgDiv = document.getElementById("recommendorg"); var html = ""; @@ -460,4 +408,4 @@ function displayOrg(json){ } } orgDiv.innerHTML = html; -} \ No newline at end of file +} diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 3536b7f43..a753f192d 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -118,7 +118,7 @@ func CreateFork(ctx *context.APIContext, form api.CreateForkOption) { forker = org } - fork, err := repo_service.ForkRepository(ctx.User, forker, repo, repo.Name, repo.Description) + fork, err := repo_service.ForkRepository(ctx.User, forker, repo, repo.Name, repo.Description, repo.Alias) if err != nil { ctx.Error(http.StatusInternalServerError, "ForkRepository", err) return diff --git a/routers/home.go b/routers/home.go index 24de1a10c..399e11997 100755 --- a/routers/home.go +++ b/routers/home.go @@ -625,11 +625,12 @@ func RecommendRepoFromPromote(ctx *context.Context) { } else { ownerName := strings.Trim(repoName[0:tmpIndex], " ") repoName := strings.Trim(repoName[tmpIndex+1:], " ") - repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + repo, err := models.GetRepositoryByOwnerAndAlias(ownerName, repoName) if err == nil { repoMap := make(map[string]interface{}) repoMap["ID"] = fmt.Sprint(repo.ID) repoMap["Name"] = repo.Name + repoMap["Alias"] = repo.Alias repoMap["OwnerName"] = repo.OwnerName repoMap["NumStars"] = repo.NumStars repoMap["NumForks"] = repo.NumForks diff --git a/routers/org/teams.go b/routers/org/teams.go index 03fbf068d..5fc0edbdd 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -143,7 +143,7 @@ func TeamsRepoAction(ctx *context.Context) { case "add": repoName := path.Base(ctx.Query("repo_name")) var repo *models.Repository - repo, err = models.GetRepositoryByName(ctx.Org.Organization.ID, repoName) + repo, err = models.GetRepositoryByOwnerAndAlias(ctx.Org.Organization.Name, repoName) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo")) diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 6621081fd..fb87241d3 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -336,6 +336,11 @@ func CloudBrainRestart(ctx *context.Context) { } func CloudBrainBenchMarkShow(ctx *context.Context) { + if benchmarkTypes == nil { + if err := json.Unmarshal([]byte(setting.BenchmarkTypes), &benchmarkTypes); err != nil { + log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", setting.BenchmarkTypes, err, ctx.Data["MsgID"]) + } + } cloudBrainShow(ctx, tplCloudBrainBenchmarkShow) } @@ -400,6 +405,21 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName) { } else { duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix) } + if benchmarkTypes != nil { + for _, benchmarkType := range benchmarkTypes.BenchmarkType { + if task.BenchmarkTypeID == benchmarkType.Id { + ctx.Data["BenchmarkTypeName"] = benchmarkType.First + for _, benchmarkChildType := range benchmarkType.Second { + if task.BenchmarkChildTypeID == benchmarkChildType.Id { + ctx.Data["BenchmarkChildTypeName"] = benchmarkChildType.Value + break + } + } + break + } + } + } + ctx.Data["duration"] = util.AddZero(duration/3600000) + ":" + util.AddZero(duration%3600000/60000) + ":" + util.AddZero(duration%60000/1000) ctx.Data["task"] = task ctx.Data["jobID"] = jobID @@ -445,7 +465,7 @@ func CloudBrainStop(ctx *context.Context) { task := ctx.Cloudbrain for { - if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) || task.Status == string(models.JobSucceeded){ + if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) || task.Status == string(models.JobSucceeded) { log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"]) resultCode = "-1" errorMsg = "system error" @@ -1180,6 +1200,7 @@ func CloudBrainBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainF benchmarkChildTypeID := form.BenchmarkChildTypeID if !jobNamePattern.MatchString(jobName) { + cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplCloudBrainBenchmarkNew, &form) return } diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 8841e4755..22ea3a54c 100755 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -105,6 +105,7 @@ func getForkRepository(ctx *context.Context) *models.Repository { return nil } ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name + ctx.Data["ForkDisplayName"] = forkRepo.FullDisplayName() ctx.Data["ForkFromOwnerID"] = forkRepo.Owner.ID if err := ctx.User.GetOwnedOrganizations(); err != nil { @@ -221,7 +222,7 @@ func ForkPost(ctx *context.Context, form auth.CreateRepoForm) { } } - repo, err := repo_service.ForkRepository(ctx.User, ctxUser, forkRepo, form.RepoName, form.Description) + repo, err := repo_service.ForkRepository(ctx.User, ctxUser, forkRepo, form.RepoName, form.Description, form.Alias) if err != nil { ctx.Data["Err_RepoName"] = true switch { diff --git a/routers/repo/repo.go b/routers/repo/repo.go index a182e9087..70705dcf1 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -6,11 +6,14 @@ package repo import ( + "code.gitea.io/gitea/modules/validation" "fmt" "net/url" "os" "path" + "regexp" "strings" + "unicode/utf8" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" @@ -201,6 +204,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) { if form.RepoTemplate > 0 { opts := models.GenerateRepoOptions{ Name: form.RepoName, + Alias: form.Alias, Description: form.Description, Private: form.Private, GitContent: form.GitContent, @@ -235,6 +239,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) { } else { repo, err = repo_service.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{ Name: form.RepoName, + Alias: form.Alias, Description: form.Description, Gitignores: form.Gitignores, IssueLabels: form.IssueLabels, @@ -358,6 +363,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { GitServiceType: gitServiceType, CloneAddr: remoteAddr, RepoName: form.RepoName, + Alias: form.Alias, Description: form.Description, Private: form.Private || setting.Repository.ForcePrivate, Mirror: form.Mirror, @@ -380,7 +386,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { opts.Releases = false } - err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName) + err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, opts.Alias) if err != nil { handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) return @@ -552,3 +558,27 @@ func Status(ctx *context.Context) { "err": task.Errors, }) } + +var repoNamePattern = regexp.MustCompile("^[0-9a-zA-Z\\.\\-_]{1,100}$") +var repoAliasPattern = regexp.MustCompile("^[\u4e00-\u9fa5\\.\\-_A-Za-z0-9]{1,100}$") + +// CheckName returns repository's default name(by given alias) +func CheckName(ctx *context.Context) { + var r = make(map[string]string, 1) + q := ctx.Query("q") + owner := ctx.Query("owner") + if q == "" || owner == "" || utf8.RuneCountInString(q) > 100 || !validation.ValidAlphaDashDotChinese(q) { + r["name"] = "" + ctx.JSON(200, r) + return + } + if repoNamePattern.MatchString(q) { + r["name"] = q + ctx.JSON(200, r) + return + } + n := models.GenerateDefaultRepoName(owner) + r["name"] = n + ctx.JSON(200, r) + return +} diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 7bb1a477b..5b057dbe5 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -6,6 +6,7 @@ package repo import ( + "code.gitea.io/gitea/modules/notification" "errors" "fmt" "io/ioutil" @@ -70,6 +71,30 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { return } + newAlias := form.Alias + var aliasChanged = false + // Check if repository alias has been changed. + if strings.ToLower(repo.Alias) != strings.ToLower(newAlias) { + aliasChanged = true + //check new alias is available or not + if err := models.IsRepositoryAliasAvailable(ctx.Repo.Owner, newAlias); err != nil { + ctx.Data["Err_Alias"] = true + switch { + case models.IsErrRepoAlreadyExist(err): + ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form) + case models.IsErrNameReserved(err): + ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplSettingsOptions, &form) + case models.IsErrNamePatternNotAllowed(err): + ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form) + default: + ctx.ServerError("ChangeRepositoryName", err) + } + return + } + + log.Trace("Repository alias changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Alias, newAlias) + } + newRepoName := form.RepoName // Check if repository name has been changed. if repo.LowerName != strings.ToLower(newRepoName) { @@ -95,12 +120,19 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName) } + //notify + if aliasChanged { + notification.NotifyRenameRepository(ctx.Repo.Owner, repo, repo.Alias) + } + // In case it's just a case change. repo.Name = newRepoName repo.LowerName = strings.ToLower(newRepoName) repo.Description = form.Description repo.Website = form.Website repo.IsTemplate = form.Template + repo.Alias = newAlias + repo.LowerAlias = strings.ToLower(newAlias) // Visibility of forked repository is forced sync with base repository. if repo.IsFork { @@ -380,7 +412,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Error(404) return } - if repo.Name != form.RepoName { + if repo.Alias != form.RepoName { ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) return } @@ -407,7 +439,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Error(404) return } - if repo.Name != form.RepoName { + if repo.Alias != form.RepoName { ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) return } @@ -445,7 +477,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Error(404) return } - if repo.Name != form.RepoName { + if repo.Alias != form.RepoName { ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) return } @@ -465,7 +497,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Error(404) return } - if repo.Name != form.RepoName { + if repo.Alias != form.RepoName { ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 76b8e9eaf..2af1b7edc 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -718,6 +718,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Combo("/:repoid").Get(repo.Fork). Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost) }, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader) + m.Get("/check_name", repo.CheckName) }, reqSignIn) // ***** Release Attachment Download without Signin diff --git a/services/repository/repository.go b/services/repository/repository.go index eafad988e..dffa1ba11 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -31,8 +31,8 @@ func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) ( } // ForkRepository forks a repository -func ForkRepository(doer, u *models.User, oldRepo *models.Repository, name, desc string) (*models.Repository, error) { - repo, err := repo_module.ForkRepository(doer, u, oldRepo, name, desc) +func ForkRepository(doer, u *models.User, oldRepo *models.Repository, name, desc, alias string) (*models.Repository, error) { + repo, err := repo_module.ForkRepository(doer, u, oldRepo, name, desc, alias) if err != nil { if repo != nil { if errDelete := models.DeleteRepository(doer, u.ID, repo.ID); errDelete != nil { diff --git a/services/repository/transfer.go b/services/repository/transfer.go index d34c812b8..0173f81d1 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -55,7 +55,7 @@ func TransferOwnership(doer, newOwner *models.User, repo *models.Repository, tea // ChangeRepositoryName changes all corresponding setting from old repository name to new one. func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoName string) error { - oldRepoName := repo.Name + //oldRepoName := repo.Name // Change repository directory name. We must lock the local copy of the // repo so that we can atomically rename the repo path and updates the @@ -68,7 +68,7 @@ func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoNam } repoWorkingPool.CheckOut(com.ToStr(repo.ID)) - notification.NotifyRenameRepository(doer, repo, oldRepoName) + //notification.NotifyRenameRepository(doer, repo, oldRepoName) return nil } diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index f946b8a46..3dee62bfb 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -36,7 +36,7 @@ {{svg "octicon-lock" 16}} {{end}} - {{.Name}} + {{.Alias}} {{.NumWatches}} {{.NumStars}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 39caa252a..25b79c99f 100755 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -25,7 +25,7 @@
@@ -55,7 +55,7 @@
diff --git a/templates/base/head_navbar_fluid.tmpl b/templates/base/head_navbar_fluid.tmpl index 6628a263d..9475f8f5f 100644 --- a/templates/base/head_navbar_fluid.tmpl +++ b/templates/base/head_navbar_fluid.tmpl @@ -25,7 +25,7 @@
@@ -54,7 +54,7 @@ diff --git a/templates/base/head_navbar_home.tmpl b/templates/base/head_navbar_home.tmpl index a74ddffaf..49b0b60e8 100644 --- a/templates/base/head_navbar_home.tmpl +++ b/templates/base/head_navbar_home.tmpl @@ -17,7 +17,7 @@ @@ -46,7 +46,7 @@ diff --git a/templates/base/head_navbar_pro.tmpl b/templates/base/head_navbar_pro.tmpl index a17c49733..0c1243fb0 100644 --- a/templates/base/head_navbar_pro.tmpl +++ b/templates/base/head_navbar_pro.tmpl @@ -26,7 +26,7 @@ @@ -56,7 +56,7 @@ diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index d7560837f..0e01186b0 100755 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -5,7 +5,7 @@ border-radius: 0.8rem; margin-bottom: 1.0rem; padding: 1.0rem !important; - } + } .ui.repository.list>.item .header { font-size: 1.4rem !important; font-weight: 200; @@ -24,7 +24,7 @@ content: ""; height: 1px; background-color: #E1E3E6; - bottom: 2.8rem; + bottom: 2.8rem; } .repository .ui.mini.menu{ font-size: .6rem; @@ -43,13 +43,13 @@ + 热门{{.i18n.Tr "explore.repos"}} + 活跃{{.i18n.Tr "explore.repos"}} {{end}} @@ -93,7 +93,7 @@
- {{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{.Name}} + {{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{.DisplayName}} {{if .IsArchived}}{{end}} {{if .IsPrivate}} @@ -114,7 +114,7 @@ - + {{.Hot}} {{else if eq $.SortType "active"}} @@ -130,7 +130,7 @@ {{svg "octicon-git-branch" 16}} {{.NumForks}} - {{end}} + {{end}} {{svg "octicon-star" 16}} {{.NumStars}} diff --git a/templates/org/repo_list.tmpl b/templates/org/repo_list.tmpl index eab03c591..c763f8976 100644 --- a/templates/org/repo_list.tmpl +++ b/templates/org/repo_list.tmpl @@ -33,7 +33,7 @@ {{end}} - {{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{.Name}} + {{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} / {{end}}{{end}}{{if .Alias}}{{.Alias}}{{else}}{{.Name}}{{end}} {{if .IsArchived}}{{end}} {{if .IsPrivate}} @@ -70,4 +70,4 @@ {{$.i18n.Tr "explore.repo_no_results"}}
{{end}} -
+ \ No newline at end of file diff --git a/templates/org/select_pro.tmpl b/templates/org/select_pro.tmpl index c88803e16..70b2a9bb3 100755 --- a/templates/org/select_pro.tmpl +++ b/templates/org/select_pro.tmpl @@ -89,7 +89,7 @@
- {{.Name}} + {{if .Alias}}{{.Alias}}{{else}}{{.Name}}{{end}}
@@ -167,6 +167,7 @@
\ No newline at end of file diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index ab4e1525b..f4127023c 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -8,12 +8,46 @@ {{.i18n.Tr "repo.settings.basic_settings"}}
-
+ {{.CsrfTokenHtml}} -
+ +
+ + + {{.i18n.Tr "form.reponame_dash_dot_error"}} +
+ +
+ +
+
+ +
+
/
+
+ + + {{.i18n.Tr "form.repoadd_dash_dot_error"}} +
+
+ +
+ +
@@ -41,7 +75,7 @@ {{end}}
- +
@@ -152,7 +186,7 @@ {{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }}
-
+
@@ -160,7 +194,7 @@ {{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }}
-
+
@@ -475,7 +509,7 @@
@@ -507,7 +541,7 @@
@@ -534,7 +568,7 @@
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}}
- {{.i18n.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}} + {{.i18n.Tr "repo.settings.delete_notices_2" .Repository.Alias | Safe}} {{if .Repository.NumForks}}
{{.i18n.Tr "repo.settings.delete_notices_fork_1"}} {{end}} @@ -545,7 +579,7 @@
@@ -569,7 +603,7 @@
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}}
- {{.i18n.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}} + {{.i18n.Tr "repo.settings.wiki_delete_notices_1" .Repository.Alias | Safe}}
{{.CsrfTokenHtml}} @@ -577,7 +611,7 @@
@@ -625,4 +659,4 @@ {{end}} {{end}} -{{template "base/footer" .}} \ No newline at end of file +{{template "base/footer" .}} diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index a1b4218dc..f3794989c 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -13,63 +13,63 @@ {{.ShortActUserName}} {{end}} {{if eq .GetOpType 1}} - {{$.i18n.Tr "action.create_repo" .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_repo" .GetRepoLink .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 2}} - {{$.i18n.Tr "action.rename_repo" .GetContent .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.rename_repo" .GetContent .GetRepoLink .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 5}} {{ $branchLink := .GetBranch | EscapePound | Escape}} - {{$.i18n.Tr "action.commit_repo" .GetRepoLink $branchLink (Escape .GetBranch) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.commit_repo" .GetRepoLink $branchLink (Escape .GetBranch) .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 6}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.create_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_issue" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 7}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.create_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 8}} - {{$.i18n.Tr "action.transfer_repo" .GetContent .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.transfer_repo" .GetContent .GetRepoLink .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 9}} {{ $branchLink := .GetBranch | EscapePound | Escape}} - {{$.i18n.Tr "action.push_tag" .GetRepoLink $branchLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.push_tag" .GetRepoLink $branchLink .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 10}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.comment_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.comment_issue" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 11}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.merge_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.merge_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 12}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.close_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.close_issue" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 13}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reopen_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reopen_issue" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 14}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.close_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.close_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 15}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 16}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.delete_tag" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.delete_tag" .GetRepoLink .GetBranch .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 17}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.delete_branch" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.delete_branch" .GetRepoLink .GetBranch .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 18}} {{ $branchLink := .GetBranch | EscapePound}} - {{$.i18n.Tr "action.mirror_sync_push" .GetRepoLink $branchLink .GetBranch .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.mirror_sync_push" .GetRepoLink $branchLink .GetBranch .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 19}} - {{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink .GetBranch .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 20}} - {{$.i18n.Tr "action.mirror_sync_delete" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.mirror_sync_delete" .GetRepoLink .GetBranch .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 21}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.approve_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.approve_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 22}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reject_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reject_pull_request" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{else if eq .GetOpType 23}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.comment_pull" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.comment_pull" .GetRepoLink $index .ShortRepoFullDisplayName | Str2html}} {{end}}

{{if or (eq .GetOpType 5) (eq .GetOpType 18)}} diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 6334ea3dc..85d1fb65c 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -107,7 +107,7 @@ {{ $timeStr:= TimeSinceUnix .CreatedUnix $.Lang }} {{if .Repo}}
  • -
    {{.Repo.FullName}}#{{.Index}}
    +
    {{.Repo.OwnerName}}/{{.Repo.Alias}}#{{.Index}}
    {{RenderEmoji .Title}} {{if .IsPull}} @@ -208,3 +208,6 @@
  • {{template "base/footer" .}} + \ No newline at end of file diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 2a4226e92..1c0ee84fc 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -65,7 +65,7 @@
    {{range .Milestones}}
  • -
    {{.Repo.FullName}}
    +
    {{.Repo.OwnerName}}/{{.Repo.Alias}}
    {{svg "octicon-milestone" 16}} {{.Name}}
    @@ -117,3 +117,6 @@
    {{template "base/footer" .}} + \ No newline at end of file diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl index dc1507403..5df52d77a 100644 --- a/templates/user/dashboard/repolist.tmpl +++ b/templates/user/dashboard/repolist.tmpl @@ -104,7 +104,7 @@
  • - ${repo.full_name} + ${repo.full_display_name} ${repo.stars_count} {{svg "octicon-star" 16}} diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index f14dc9b7a..d42ed4058 100755 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -51,7 +51,7 @@
  • {{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}
  • {{if and .Orgs .HasOrgsVisible}} -
  • 组织
  • +
  • {{.i18n.Tr "organization"}}