Browse Source

解决冲突

Signed-off-by: zouap <zouap@pcl.ac.cn>
tags/v1.22.3.2^2
zouap 4 years ago
parent
commit
731016d5de
24 changed files with 286 additions and 138 deletions
  1. +18
    -0
      models/action.go
  2. +61
    -65
      models/repo.go
  3. +1
    -0
      models/repo_generate.go
  4. +3
    -2
      models/repo_list.go
  5. +2
    -0
      modules/auth/auth.go
  6. +3
    -0
      modules/auth/repo_form.go
  7. +1
    -0
      modules/repository/create.go
  8. +1
    -0
      modules/repository/fork.go
  9. +1
    -0
      modules/repository/generate.go
  10. +27
    -25
      modules/structs/repo.go
  11. +1
    -0
      modules/task/task.go
  12. +24
    -0
      modules/validation/binding.go
  13. +5
    -3
      options/locale/locale_en-US.ini
  14. +3
    -1
      options/locale/locale_zh-CN.ini
  15. +30
    -1
      routers/repo/repo.go
  16. +1
    -0
      routers/repo/setting.go
  17. +1
    -0
      routers/routes/routes.go
  18. +7
    -7
      templates/explore/repo_list.tmpl
  19. +85
    -24
      templates/repo/create.tmpl
  20. +4
    -4
      templates/repo/header.tmpl
  21. +2
    -1
      templates/repo/settings/options.tmpl
  22. +3
    -3
      templates/user/dashboard/feeds.tmpl
  23. +1
    -1
      templates/user/dashboard/repolist.tmpl
  24. +1
    -1
      templates/user/settings/repos.tmpl

+ 18
- 0
models/action.go View File

@@ -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 {


+ 61
- 65
models/repo.go View File

@@ -6,12 +6,13 @@
package models

import (
"code.gitea.io/gitea/modules/git"
"context"
"crypto/md5"
"errors"
"fmt"
"html/template"
"math/rand"

"xorm.io/xorm"

"code.gitea.io/gitea/modules/blockchain"
@@ -223,6 +224,7 @@ type Repository struct {

Hot int64 `xorm:"-"`
Active int64 `xorm:"-"`
Alias string
}

// SanitizedOriginalURL returns a sanitized OriginalURL
@@ -233,6 +235,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 +296,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()
@@ -386,6 +401,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
Owner: repo.Owner.APIFormat(),
Name: repo.Name,
FullName: repo.FullName(),
FullDisplayName: repo.FullDisplayName(),
Description: repo.Description,
Private: repo.IsPrivate,
Template: repo.IsTemplate,
@@ -921,17 +937,24 @@ 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{"alias": alias}, builder.Eq{"lower_name": repoName})
cond = cond.And(subCon)
} else {
cond = cond.And(builder.Eq{"lower_name": repoName})
}
count, err := e.Where(cond).Count(&Repository{})
//todo 确定从 && 改成 || 是否有问题
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)
}

// CloneLink represents different types of clone URLs of repository.
@@ -975,20 +998,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
}

if err := IsUsableRepoAlias(alias); err != nil {
return err
}

has, err := isRepositoryExist(x, u, name)
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 +1023,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 +1064,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 +1075,21 @@ 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) {
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 +1271,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 +1404,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 {
@@ -2521,52 +2559,10 @@ func UpdateRepositoryCommitNum(repo *Repository) error {
return nil
}

type RepoFile struct {
CommitId string
Content []byte
}

// ReadLatestFileInRepo read latest version of file in repository
// return a RepoFile
func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFile, error) {
var err error
repoPath := RepoPath(userName, repoName)
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
log.Error("ReadLatestFileInRepo error when OpenRepository,error=%v", err)
return nil, err
}
commitID, err := gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommitID,error=%v", err)
return nil, err
}
commit, err := gitRepo.GetBranchCommit(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommit,error=%v", err)
return nil, err
}

blob, err := commit.GetBlobByPath(treePath)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBlobByPath,error=%v", err)
return nil, err
}

reader, err := blob.DataAsync()
if err != nil {
return nil, err
}
defer func() {
if err = reader.Close(); err != nil {
log.Error("ReadLatestFileInRepo: Close: %v", err)
}
}()

buf := make([]byte, 1024)
n, _ := reader.Read(buf)
if n >= 0 {
buf = buf[:n]
func GenerateDefaultRepoName(ownerName string) string {
if len(ownerName) > 5 {
ownerName = ownerName[:5]
}
return &RepoFile{CommitId: commitID, Content: buf}, nil
now := time.Now().Format("20060102150405")
return ownerName + now + fmt.Sprint(rand.Intn(10))
}

+ 1
- 0
models/repo_generate.go View File

@@ -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


+ 3
- 2
models/repo_list.go View File

@@ -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", strings.ToLower(v)})
if opts.IncludeDescription {
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})
}


+ 2
- 0
modules/auth/auth.go View File

@@ -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
}


+ 3
- 0
modules/auth/repo_form.go View File

@@ -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


+ 1
- 0
modules/repository/create.go View File

@@ -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,


+ 1
- 0
modules/repository/fork.go View File

@@ -33,6 +33,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
Owner: owner,
OwnerName: owner.Name,
Name: name,
Alias: oldRepo.Alias,
LowerName: strings.ToLower(name),
Description: desc,
DefaultBranch: oldRepo.DefaultBranch,


+ 1
- 0
modules/repository/generate.go View File

@@ -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,


+ 27
- 25
modules/structs/repo.go View File

@@ -46,31 +46,32 @@ 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"`
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 +218,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"`


+ 1
- 0
modules/task/task.go View File

@@ -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,


+ 24
- 0
modules/validation/binding.go View File

@@ -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)
}

+ 5
- 3
options/locale/locale_en-US.ini View File

@@ -346,7 +346,8 @@ modify = Update

[form]
UserName = Username
RepoName = Repository name
Alias = Repository name
RepoName = Repository path
Email = Email address
Password = Password
Retype = Re-Type Password
@@ -371,6 +372,7 @@ 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.`
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.`
@@ -894,7 +896,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
@@ -1174,7 +1176,7 @@ issues.filter_label_exclude = `Use <code>alt</code> + <code>click/enter</code> 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


+ 3
- 1
options/locale/locale_zh-CN.ini View File

@@ -350,7 +350,8 @@ modify=更新

[form]
UserName=用户名
RepoName=项目名称
RepoName=项目路径
Alias=项目名称
Email=邮箱地址
Password=密码
Retype=重新输入密码
@@ -375,6 +376,7 @@ require_error=不能为空。
alpha_dash_error=应该只包含字母数字、破折号 ('-') 和下划线 ('_') 字符。
alpha_dash_dot_error=应该只包含字母数字, 破折号 ('-'), 下划线 ('_') 和点 ('. ') 。
git_ref_name_error=` 必须是格式良好的 git 引用名称。`
alpha_dash_dot_chinese_error=应该只包含字母数字中文, 破折号 ('-'), 下划线 ('_') 和点 ('. ') 。
size_error=长度必须为 %s。
min_size_error=长度最小为 %s 个字符。
max_size_error=长度最大为 %s 个字符。


+ 30
- 1
routers/repo/repo.go View File

@@ -6,10 +6,12 @@
package repo

import (
"code.gitea.io/gitea/modules/validation"
"fmt"
"net/url"
"os"
"path"
"regexp"
"strings"

"code.gitea.io/gitea/models"
@@ -201,6 +203,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 +238,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 +362,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 +385,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 +557,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 == "" || len(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
}

+ 1
- 0
routers/repo/setting.go View File

@@ -98,6 +98,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
repo.Description = form.Description
repo.Website = form.Website
repo.IsTemplate = form.Template
repo.Alias = form.Alias

// Visibility of forked repository is forced sync with base repository.
if repo.IsFork {


+ 1
- 0
routers/routes/routes.go View File

@@ -719,6 +719,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


+ 7
- 7
templates/explore/repo_list.tmpl View File

@@ -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 @@
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot&tab={{$.TabName}}">
<svg class="svg octicon-repo" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-repo" />
</svg>
</svg>
热门{{.i18n.Tr "explore.repos"}}
</a>
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active&tab={{$.TabName}}">
<svg class="svg octicon-inbox" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-inbox" />
</svg>
</svg>
活跃{{.i18n.Tr "explore.repos"}}
</a>
{{end}}
@@ -93,7 +93,7 @@
<div class="ui grid">
<div class="ui sixteen wide mobile ten wide tablet twelve wide computer column">
<a class="name" href="{{.Link}}">
{{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} <span>/</span> {{end}}{{end}}<strong>{{.Name}}</strong>
{{if or $.PageIsExplore $.PageIsProfileStarList }}{{if .Owner}}{{.Owner.Name}} <span>/</span> {{end}}{{end}}<strong>{{.DisplayName}}</strong>
{{if .IsArchived}}<i class="archive icon archived-icon"></i>{{end}}
</a>
{{if .IsPrivate}}
@@ -114,7 +114,7 @@
<a class="item">
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24">
<path fill="currentColor" d="M17.66 11.2C17.43 10.9 17.15 10.64 16.89 10.38C16.22 9.78 15.46 9.35 14.82 8.72C13.33 7.26 13 4.85 13.95 3C13 3.23 12.17 3.75 11.46 4.32C8.87 6.4 7.85 10.07 9.07 13.22C9.11 13.32 9.15 13.42 9.15 13.55C9.15 13.77 9 13.97 8.8 14.05C8.57 14.15 8.33 14.09 8.14 13.93C8.08 13.88 8.04 13.83 8 13.76C6.87 12.33 6.69 10.28 7.45 8.64C5.78 10 4.87 12.3 5 14.47C5.06 14.97 5.12 15.47 5.29 15.97C5.43 16.57 5.7 17.17 6 17.7C7.08 19.43 8.95 20.67 10.96 20.92C13.1 21.19 15.39 20.8 17.03 19.32C18.86 17.66 19.5 15 18.56 12.72L18.43 12.46C18.22 12 17.66 11.2 17.66 11.2M14.5 17.5C14.22 17.74 13.76 18 13.4 18.1C12.28 18.5 11.16 17.94 10.5 17.28C11.69 17 12.4 16.12 12.61 15.23C12.78 14.43 12.46 13.77 12.33 13C12.21 12.26 12.23 11.63 12.5 10.94C12.69 11.32 12.89 11.7 13.13 12C13.9 13 15.11 13.44 15.37 14.8C15.41 14.94 15.43 15.08 15.43 15.23C15.46 16.05 15.1 16.95 14.5 17.5H14.5Z" />
</svg>
</svg>
{{.Hot}}
</a>
{{else if eq $.SortType "active"}}
@@ -130,7 +130,7 @@
<a class="item">
{{svg "octicon-git-branch" 16}} {{.NumForks}}
</a>
{{end}}
{{end}}
<a class="item">
{{svg "octicon-star" 16}} {{.NumStars}}
</a>


+ 85
- 24
templates/repo/create.tmpl View File

@@ -9,36 +9,55 @@
</h3>
<div class="ui attached segment">
{{template "base/alert" .}}
<div class="inline required field {{if .Err_Owner}}error{{end}}">
<label>{{.i18n.Tr "repo.owner"}}</label>
<div class="ui selection owner dropdown">
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
<span class="text" title="{{.ContextUser.Name}}">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
{{.ContextUser.ShortName 20}}
</span>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="{{.SignedUser.ID}}" title="{{.SignedUser.Name}}">
<img class="ui mini image" src="{{.SignedUser.RelAvatarLink}}">
{{.SignedUser.ShortName 20}}
</div>
{{range .Orgs}}
<div class="item" data-value="{{.ID}}" title="{{.Name}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
{{.ShortName 20}}
<div class="inline required field">
<label for="Alias">项目名称</label>
<input id="alias" name="alias" value="" oninput="throttle()" autofocus required>
<!-- <span class="help"></span> -->
</div>

<div class="inline required fields">
<label style="text-align: right;width: 250px!important;word-wrap: break-word;">项目路径</label>
<div class="required field {{if .Err_Owner}}error{{end}}" style="padding: 0;">
<!-- <label>{{.i18n.Tr "repo.owner"}}</label> -->
<div class="ui selection owner dropdown">
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
<span class="text" title="{{.ContextUser.Name}}">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
{{.ContextUser.ShortName 20}}
</span>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="{{.SignedUser.ID}}" title="{{.SignedUser.Name}}">
<img class="ui mini image" src="{{.SignedUser.RelAvatarLink}}">
{{.SignedUser.ShortName 20}}
</div>
{{end}}
{{range .Orgs}}
<div class="item" data-value="{{.ID}}" title="{{.Name}}">
<img class="ui mini image" src="{{.RelAvatarLink}}">
{{.ShortName 20}}
</div>
{{end}}
</div>
</div>
<!-- <span class="help">{{.i18n.Tr "repo.repo_owner_helper"}}</span> -->
</div>
<!-- <div class="required field {{if .Err_RepoName}}error{{end}}">
<input id="repo_name" name="repo_name" value="{{.repo_name}}" autofocus required>
</div> -->
<div class="ui interval" style="width: 0.6em;font-size: 2rem;line-height: 0px;text-align: center;">/</div>
<div class="required field {{if .Err_RepoName}}error{{end}}">
<!-- <label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> -->
<input style="width: 100% !important;" id="repo_name" name="repo_name" value="{{.repo_name}}" autofocus required>
</div>
<span class="help">{{.i18n.Tr "repo.repo_owner_helper"}}</span>
</div>

<div class="inline required field {{if .Err_RepoName}}error{{end}}">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" value="{{.repo_name}}" autofocus required>
<span class="help"></span>
<div class="inline field">
<label for=""></label>
<span id="repoAdress" style="display: none;margin-bottom: 1rem;"></span>
</div>
<!-- <div class="js-project-full-path" id="repoAdress" ></div> -->
<div class="inline field">
<label>{{.i18n.Tr "repo.visibility"}}</label>
<div class="ui checkbox">
@@ -183,3 +202,45 @@
</div>
</div>
{{template "base/footer" .}}
<script>
$('#alias').bind('input propertychange', function (event) {
});
console.log()
let timeout;
let keydown_flag = false
$('#repo_name').keyup(function(){
keydown_flag = $('#repo_name').val() ? true : false
if(keydown_flag){
$('#repoAdress').css("display","block")
$('#repoAdress').text("{{.i18n.Tr "repo.template.topics"}}:"+$('#repo_name').val())
}
})
function throttle(){
//先清理
clearTimeout(timeout)
timeout = setTimeout(() => {
//在此处写调用的方法,可以实现仅最后一次操作生效
const aliasValue = $('#alias').val()
const ownerValue = $('#uid').val()
if(keydown_flag){
$('#repo_name').attr("placeholder","")
}
else if(aliasValue){
$('#repo_name').attr("placeholder","正在获取路径...")
$.get(`${window.config.AppSubUrl}/repo/check_name?q=${aliasValue}&owner=${ownerValue }`,(data)=>{
const repo_name = data.name
$('#repo_name').val(repo_name)
$('#repoAdress').css("display","block")
$('#repoAdress').text("{{.i18n.Tr "repo.template.topics"}}:"+$('#repo_name').val())
})
}else{
$('#repo_name').val('')
$('#repo_name').attr("placeholder","")
}
}, 500)
}


</script>

+ 4
- 4
templates/repo/header.tmpl View File

@@ -24,7 +24,7 @@
{{end}}
<a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a>
<div class="divider"> / </div>
<a href="{{$.RepoLink}}">{{.Name}}</a>
<a href="{{$.RepoLink}}">{{.DisplayName}}</a>
{{if .RelAvatarLink}}
{{if .IsTemplate}}
{{if .IsPrivate}}
@@ -114,9 +114,9 @@
{{end}}
</div>
</div>
{{end}}


{{if .Permission.CanRead $.UnitTypeIssues}}
@@ -152,7 +152,7 @@
{{if .Permission.CanRead $.UnitTypeCloudBrain}}
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/debugjob?debugListType=all">
<span>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"/></svg>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"/></svg>
{{.i18n.Tr "repo.cloudbrain"}}
<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i>
</span>


+ 2
- 1
templates/repo/settings/options.tmpl View File

@@ -13,7 +13,8 @@
<input type="hidden" name="action" value="update">
<div class="required field {{if .Err_RepoName}}error{{end}}">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required>
<input id="repo_name" name="alias" value="{{.Repository.Alias}}" data-repo-name="{{.Repository.Alias}}" autofocus required>
<input type="hidden" name="repo_name" value="{{.Repository.Name}}" data-repo-name="{{.Repository.Name}}" autofocus required>
</div>
<div class="inline field">
<label>{{.i18n.Tr "repo.repo_size"}}</label>


+ 3
- 3
templates/user/dashboard/feeds.tmpl View File

@@ -13,12 +13,12 @@
{{.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}}


+ 1
- 1
templates/user/dashboard/repolist.tmpl View File

@@ -104,7 +104,7 @@
<li v-for="repo in repos" :class="{'private': repo.private}" v-show="showRepo(repo)">
<a :href="suburl + '/' + repo.full_name">
<svg :class="'svg ' + repoClass(repo)" width="16" height="16" aria-hidden="true"><use :xlink:href="'#' + repoClass(repo)" /></svg>
<strong class="text truncate item-name">${repo.full_name}</strong>
<strong class="text truncate item-name">${repo.full_display_name}</strong>
<i v-if="repo.archived" class="archive icon archived-icon"></i>
<span class="ui right text light grey">
${repo.stars_count} <span class="rear">{{svg "octicon-star" 16}}</span>


+ 1
- 1
templates/user/settings/repos.tmpl View File

@@ -21,7 +21,7 @@
{{else}}
<span class="iconFloat">{{svg "octicon-repo" 16}}</span>
{{end}}
<a class="name" href="{{AppSubUrl}}/{{$.Owner.Name}}/{{.Name}}">{{$.Owner.Name}}/{{.Name}}</a>
<a class="name" href="{{AppSubUrl}}/{{$.Owner.Name}}/{{.Name}}">{{$.Owner.Name}}/{{.DisplayName}}</a>
<span>{{SizeFmt .Size}}</span>
{{if .IsFork}}
{{$.i18n.Tr "repo.forked_from"}}


Loading…
Cancel
Save