diff --git a/models/user_mail.go b/models/user_mail.go old mode 100644 new mode 100755 index af9602e71..7244ec378 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -80,6 +80,18 @@ func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) { return email, nil } +// GetEmailAddressByIDAndEmail gets a user's email address by ID and email +func GetEmailAddressByIDAndEmail(uid int64, emailAddr string) (*EmailAddress, error) { + // User ID is required for security reasons + email := &EmailAddress{UID: uid, Email: emailAddr} + if has, err := x.Get(email); err != nil { + return nil, err + } else if !has { + return nil, nil + } + return email, nil +} + func isEmailActive(e Engine, email string, userID, emailID int64) (bool, error) { if len(email) == 0 { return true, nil diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index b59f4ffc7..fea7a3384 100755 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -141,6 +141,35 @@ func DeleteAttachment(ctx *context.Context) { }) } +func DownloadUserIsOrgOrCollaboration(ctx *context.Context, attach *models.Attachment) bool { + dataset, err := models.GetDatasetByID(attach.DatasetID) + if err != nil { + log.Info("query dataset error") + } else { + repo, err := models.GetRepositoryByID(dataset.RepoID) + if err != nil { + log.Info("query repo error.") + } else { + repo.GetOwner() + if ctx.User != nil { + + if repo.Owner.IsOrganization() { + if repo.Owner.IsUserPartOfOrg(ctx.User.ID) { + log.Info("org user may visit the attach.") + return true + } + } + isCollaborator, _ := repo.IsCollaborator(ctx.User.ID) + if isCollaborator { + log.Info("Collaborator user may visit the attach.") + return true + } + } + } + } + return false +} + // GetAttachment serve attachements func GetAttachment(ctx *context.Context) { typeCloudBrain := ctx.QueryInt("type") @@ -165,16 +194,29 @@ func GetAttachment(ctx *context.Context) { ctx.ServerError("LinkedRepository", err) return } + dataSet, err := attach.LinkedDataSet() + if err != nil { + ctx.ServerError("LinkedDataSet", err) + return + } + + if repository == nil && dataSet != nil { + repository, _ = models.GetRepositoryByID(dataSet.RepoID) + unitType = models.UnitTypeDatasets + } if repository == nil { //If not linked - if !(ctx.IsSigned && attach.UploaderID == ctx.User.ID) && attach.IsPrivate { //We block if not the uploader + //if !(ctx.IsSigned && attach.UploaderID == ctx.User.ID) && attach.IsPrivate { //We block if not the uploader + //log.Info("ctx.IsSigned =" + fmt.Sprintf("%v", ctx.IsSigned)) + if !(ctx.IsSigned && attach.UploaderID == ctx.User.ID) && attach.IsPrivate && !DownloadUserIsOrgOrCollaboration(ctx, attach) { //We block if not the uploader ctx.Error(http.StatusNotFound) return } + } else { //If we have the repository we check access - perm, err := models.GetUserRepoPermission(repository, ctx.User) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error()) + perm, errPermission := models.GetUserRepoPermission(repository, ctx.User) + if errPermission != nil { + ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", errPermission.Error()) return } if !perm.CanRead(unitType) { @@ -183,12 +225,6 @@ func GetAttachment(ctx *context.Context) { } } - dataSet, err := attach.LinkedDataSet() - if err != nil { - ctx.ServerError("LinkedDataSet", err) - return - } - if dataSet != nil { isPermit, err := models.GetUserDataSetPermission(dataSet, ctx.User) if err != nil { @@ -205,7 +241,7 @@ func GetAttachment(ctx *context.Context) { if setting.Attachment.StoreType == storage.MinioStorageType { url := "" if typeCloudBrain == models.TypeCloudBrainOne { - url, err = storage.Attachments.PresignedGetURL(setting.Attachment.Minio.BasePath + attach.RelativePath(), attach.Name) + url, err = storage.Attachments.PresignedGetURL(setting.Attachment.Minio.BasePath+attach.RelativePath(), attach.Name) if err != nil { ctx.ServerError("PresignedGetURL", err) return diff --git a/routers/repo/dataset.go b/routers/repo/dataset.go index 3be36fbe4..b2da4b8d8 100755 --- a/routers/repo/dataset.go +++ b/routers/repo/dataset.go @@ -1,15 +1,13 @@ package repo import ( - "sort" - - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "sort" ) const ( @@ -24,19 +22,42 @@ func MustEnableDataset(ctx *context.Context) { } } -func filterPrivateAttachments(ctx *context.Context, list []*models.Attachment) []*models.Attachment { +func newFilterPrivateAttachments(ctx *context.Context, list []*models.Attachment, repo *models.Repository) []*models.Attachment { + if ctx.Repo.CanWrite(models.UnitTypeDatasets) { + log.Info("can write.") return list } else { + if repo.Owner == nil { + repo.GetOwner() + } + permission := false + if repo.Owner.IsOrganization() && ctx.User != nil { + if repo.Owner.IsUserPartOfOrg(ctx.User.ID) { + log.Info("user is member of org.") + permission = true + } + } + if !permission && ctx.User != nil { + isCollaborator, _ := repo.IsCollaborator(ctx.User.ID) + if isCollaborator { + log.Info("Collaborator user may visit the attach.") + permission = true + } + } + var publicList []*models.Attachment for _, attach := range list { if !attach.IsPrivate { publicList = append(publicList, attach) + } else { + if permission { + publicList = append(publicList, attach) + } } } return publicList } - } func DatasetIndex(ctx *context.Context) { @@ -60,7 +81,7 @@ func DatasetIndex(ctx *context.Context) { ctx.ServerError("GetDatasetAttachments", err) return } - attachments := filterPrivateAttachments(ctx, dataset.Attachments) + attachments := newFilterPrivateAttachments(ctx, dataset.Attachments, repo) ctx.Data["SortType"] = ctx.Query("sort") switch ctx.Query("sort") { diff --git a/routers/repo/view.go b/routers/repo/view.go index 76593ecc7..945f6b0e0 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -569,10 +569,19 @@ func safeURL(address string) string { } type ContributorInfo struct { - UserInfo *models.User - Email string // for contributor who is not a registered user + UserInfo *models.User // nil for contributor who is not a registered user + Email string + CommitCnt int } +func getContributorInfo(contributorInfos []*ContributorInfo, email string) *ContributorInfo{ + for _, c := range contributorInfos { + if strings.Compare(c.Email,email) == 0 { + return c + } + } + return nil +} // Home render repository home page func Home(ctx *context.Context) { if len(ctx.Repo.Units) > 0 { @@ -581,15 +590,31 @@ func Home(ctx *context.Context) { if err == nil && contributors != nil { var contributorInfos []*ContributorInfo for _, c := range contributors { + // get user info from committer email user, err := models.GetUserByEmail(c.Email) if err == nil { - contributorInfos = append(contributorInfos, &ContributorInfo{ - user, c.Email, - }) + // committer is system user, get info through user's primary email + existedContributorInfo := getContributorInfo(contributorInfos,user.Email) + if existedContributorInfo != nil { + // existed: same primary email, different committer name + existedContributorInfo.CommitCnt += c.CommitCnt + }else{ + // new committer info + contributorInfos = append(contributorInfos, &ContributorInfo{ + user, user.Email,c.CommitCnt, + }) + } } else { - contributorInfos = append(contributorInfos, &ContributorInfo{ - nil, c.Email, - }) + // committer is not system user + existedContributorInfo := getContributorInfo(contributorInfos,c.Email) + if existedContributorInfo != nil { + // existed: same primary email, different committer name + existedContributorInfo.CommitCnt += c.CommitCnt + }else{ + contributorInfos = append(contributorInfos, &ContributorInfo{ + nil, c.Email,c.CommitCnt, + }) + } } } ctx.Data["ContributorInfo"] = contributorInfos diff --git a/routers/secure/user.go b/routers/secure/user.go index 8c06b0dab..1e88a7381 100755 --- a/routers/secure/user.go +++ b/routers/secure/user.go @@ -104,6 +104,21 @@ func CreateUser(ctx *context.Context, form api.CreateUserOption) { } return } + + err := models.AddEmailAddress(&models.EmailAddress{ + UID: u.ID, + Email: form.Email, + IsActivated: !setting.Service.RegisterEmailConfirm, + }) + + if err != nil { + log.Error("AddEmailAddress failed:%v", err.Error(), ctx.Data["MsgID"]) + ctx.JSON(http.StatusInternalServerError, map[string]string{ + "error_msg": err.Error(), + }) + return + } + log.Trace("Account created (%s): %s", ctx.User.Name, u.Name, ctx.Data["MsgID"]) // Send email notification. diff --git a/routers/user/auth.go b/routers/user/auth.go index dc5c5536b..13e338565 100755 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -1165,7 +1165,19 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo } return } - log.Trace("Account created: %s", u.Name) + log.Trace("Account created: %s", u.Name, ctx.Data["MsgID"]) + + err := models.AddEmailAddress(&models.EmailAddress{ + UID: u.ID, + Email: form.Email, + IsActivated: !setting.Service.RegisterEmailConfirm, + }) + + if err != nil { + log.Error("AddEmailAddress failed:%v", err.Error(), ctx.Data["MsgID"]) + ctx.ServerError("AddEmailAddress", err) + return + } // Auto-set admin for the only user. if models.CountUsers() == 1 { @@ -1254,6 +1266,15 @@ func Activate(ctx *context.Context) { log.Error("Error storing session: %v", err) } + email, err := models.GetEmailAddressByIDAndEmail(user.ID, user.Email) + if err != nil || email == nil{ + log.Error("GetEmailAddressByIDAndEmail failed", ctx.Data["MsgID"]) + } else { + if err := email.Activate(); err != nil { + log.Error("Activate failed: %v", err, ctx.Data["MsgID"]) + } + } + ctx.Flash.Success(ctx.Tr("auth.account_activated")) ctx.Redirect(setting.AppSubURL + "/") return diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go old mode 100644 new mode 100755 index d6f25f913..a385f2cac --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -96,6 +96,18 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { ctx.User.Location = form.Location ctx.User.Language = form.Language ctx.User.Description = form.Description + isUsed, err := models.IsEmailUsed(form.Email) + if err != nil { + ctx.ServerError("IsEmailUsed", err) + return + } + + if isUsed { + ctx.Flash.Error(ctx.Tr("form.email_been_used")) + ctx.Redirect(setting.AppSubURL + "/user/settings") + return + } + if err := models.UpdateUserSetting(ctx.User); err != nil { if _, ok := err.(models.ErrEmailAlreadyUsed); ok { ctx.Flash.Error(ctx.Tr("form.email_been_used")) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 7d632ea14..75cee742e 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -4,6 +4,48 @@ font-size: 1.0em; margin-bottom: 1.0rem; } +#contributorInfo > a:nth-child(n+25){ + display:none; +} +#contributorInfo > a{ + width: 2.0em; + float: left; + margin: .25em; +} +#contributorInfo > a.circular{ + height: 2.0em; + padding: 0; + overflow: hidden; + letter-spacing:1.0em; + text-indent: 0.6em; + line-height: 2.0em; + text-transform:capitalize; + color: #FFF; +} +#contributorInfo > a.circular:nth-child(9n+1){ + background-color: #4ccdec; +} +#contributorInfo > a.circular:nth-child(9n+2){ + background-color: #e0b265; +} +#contributorInfo > a.circular:nth-child(9n+3){ + background-color: #d884b7; +} +#contributorInfo > a.circular:nth-child(9n+4){ + background-color: #8c6bdc; +} +#contributorInfo > a.circular:nth-child(9n+5){ + background-color: #3cb99f; +} +#contributorInfo > a.circular:nth-child(9n+6){ + background-color: #6995b9; +} +#contributorInfo > a.circular:nth-child(9n+7){ + background-color: #ab91a7; +} +#contributorInfo > a.circular:nth-child(9n+8){ + background-color: #bfd0aa; +}
{{template "repo/header" .}} @@ -193,17 +235,15 @@

贡献者 ({{len .ContributorInfo}})

- -
+
{{range .ContributorInfo}} - {{/*  {{.UserInfo.Name}}*/}} {{if .UserInfo}} - + {{else if .Email}} - + {{.Email}} {{end}} {{end}}
@@ -215,4 +255,12 @@
+ + {{template "base/footer" .}} diff --git a/web_src/js/components/MinioUploader.vue b/web_src/js/components/MinioUploader.vue index 9d845650a..1dc92e4b3 100755 --- a/web_src/js/components/MinioUploader.vue +++ b/web_src/js/components/MinioUploader.vue @@ -335,6 +335,7 @@ export default { async function uploadMinio(url, e) { const res = await axios.put(url, e.target.result); + delete e.target.result etags[currentChunk] = res.headers.etag; } diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 0382595b3..9103d7e24 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -2685,7 +2685,7 @@ tbody.commit-list { width: 1127px; } th .message-wrapper { - max-width: 680px; + max-width: 510px; } }