Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/221 Reviewed-by: zouap <zouap@pcl.ac.cn>pull/236/head
@@ -976,12 +976,12 @@ func CreateUser(u *User) (err error) { | |||||
result, err := blockchain.CreateBlockchainAccount() | result, err := blockchain.CreateBlockchainAccount() | ||||
if err != nil { | if err != nil { | ||||
log.Error("createBlockchainAccount failed:", err.Error()) | log.Error("createBlockchainAccount failed:", err.Error()) | ||||
return err | |||||
//return err | |||||
} else { | |||||
u.PublicKey = result.Payload["publickey"].(string) | |||||
u.PrivateKey = result.Payload["privatekey"].(string) | |||||
} | } | ||||
u.PublicKey = result.Payload["publickey"].(string) | |||||
u.PrivateKey = result.Payload["privatekey"].(string) | |||||
sess := x.NewSession() | sess := x.NewSession() | ||||
defer sess.Close() | defer sess.Close() | ||||
if err = sess.Begin(); err != nil { | if err = sess.Begin(); err != nil { | ||||
@@ -80,6 +80,18 @@ func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) { | |||||
return email, nil | 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) { | func isEmailActive(e Engine, email string, userID, emailID int64) (bool, error) { | ||||
if len(email) == 0 { | if len(email) == 0 { | ||||
return true, nil | return true, nil | ||||
@@ -335,6 +335,7 @@ func ToUser(user *models.User, signed, authed bool) *api.User { | |||||
AvatarURL: user.AvatarLink(), | AvatarURL: user.AvatarLink(), | ||||
FullName: markup.Sanitize(user.FullName), | FullName: markup.Sanitize(user.FullName), | ||||
Created: user.CreatedUnix.AsTime(), | Created: user.CreatedUnix.AsTime(), | ||||
IsActive: user.IsActive, | |||||
} | } | ||||
// hide primary email if API caller is anonymous or user keep email private | // hide primary email if API caller is anonymous or user keep email private | ||||
if signed && (!user.KeepEmailPrivate || authed) { | if signed && (!user.KeepEmailPrivate || authed) { | ||||
@@ -26,6 +26,8 @@ type User struct { | |||||
Language string `json:"language"` | Language string `json:"language"` | ||||
// Is the user an administrator | // Is the user an administrator | ||||
IsAdmin bool `json:"is_admin"` | IsAdmin bool `json:"is_admin"` | ||||
// Is the user active | |||||
IsActive bool `json:"is_active"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
LastLogin time.Time `json:"last_login,omitempty"` | LastLogin time.Time `json:"last_login,omitempty"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
@@ -90,7 +90,7 @@ loading = Loading… | |||||
error404_index = Request forbidden by administrative rules | error404_index = Request forbidden by administrative rules | ||||
error500_index = Internal Server Error | error500_index = Internal Server Error | ||||
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it. | error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it. | ||||
error500= Sorry, the site has encountered some problems, we are trying to <strong>fix the page</strong>, please try again later. | |||||
[error] | [error] | ||||
occurred = An error has occurred | occurred = An error has occurred | ||||
report_message = An error has occurred | report_message = An error has occurred | ||||
@@ -90,6 +90,7 @@ loading=正在加载... | |||||
error404_index = 您的访问受限! | error404_index = 您的访问受限! | ||||
error500_index = 抱歉!您指定的网页无法访问。 | error500_index = 抱歉!您指定的网页无法访问。 | ||||
error404=您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。 | error404=您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。 | ||||
error500=抱歉,站点遇到一些问题,我们正尝试<strong>修复网页</strong>,请您稍后再试。 | |||||
[error] | [error] | ||||
occurred=发生错误 | occurred=发生错误 | ||||
@@ -1841,6 +1841,14 @@ | |||||
"async-done": "^1.2.2" | "async-done": "^1.2.2" | ||||
} | } | ||||
}, | }, | ||||
"async-validator": { | |||||
"version": "1.8.5", | |||||
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", | |||||
"integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", | |||||
"requires": { | |||||
"babel-runtime": "6.x" | |||||
} | |||||
}, | |||||
"asynckit": { | "asynckit": { | ||||
"version": "0.4.0", | "version": "0.4.0", | ||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | ||||
@@ -1934,6 +1942,11 @@ | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
"babel-helper-vue-jsx-merge-props": { | |||||
"version": "2.0.3", | |||||
"resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", | |||||
"integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" | |||||
}, | |||||
"babel-loader": { | "babel-loader": { | ||||
"version": "8.1.0", | "version": "8.1.0", | ||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", | "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", | ||||
@@ -3882,6 +3895,26 @@ | |||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.437.tgz", | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.437.tgz", | ||||
"integrity": "sha512-PBQn2q68ErqMyBUABh9Gh8R6DunGky8aB5y3N5lPM7OVpldwyUbAK5AX9WcwE/5F6ceqvQ+iQLYkJYRysAs6Bg==" | "integrity": "sha512-PBQn2q68ErqMyBUABh9Gh8R6DunGky8aB5y3N5lPM7OVpldwyUbAK5AX9WcwE/5F6ceqvQ+iQLYkJYRysAs6Bg==" | ||||
}, | }, | ||||
"element-ui": { | |||||
"version": "2.15.5", | |||||
"resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.5.tgz", | |||||
"integrity": "sha512-B/YCdz2aRY2WnFXzbTRTHPKZHBD/2KV6u88EBnkaARC/Lyxnap+7vpvrcW5UNTyVwjItS5Fj1eQyRy6236lbXg==", | |||||
"requires": { | |||||
"async-validator": "~1.8.1", | |||||
"babel-helper-vue-jsx-merge-props": "^2.0.0", | |||||
"deepmerge": "^1.2.0", | |||||
"normalize-wheel": "^1.0.1", | |||||
"resize-observer-polyfill": "^1.5.0", | |||||
"throttle-debounce": "^1.0.1" | |||||
}, | |||||
"dependencies": { | |||||
"deepmerge": { | |||||
"version": "1.5.2", | |||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", | |||||
"integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" | |||||
} | |||||
} | |||||
}, | |||||
"elliptic": { | "elliptic": { | ||||
"version": "6.5.4", | "version": "6.5.4", | ||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", | ||||
@@ -9186,6 +9219,11 @@ | |||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", | ||||
"integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" | "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" | ||||
}, | }, | ||||
"normalize-wheel": { | |||||
"version": "1.0.1", | |||||
"resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", | |||||
"integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" | |||||
}, | |||||
"now-and-later": { | "now-and-later": { | ||||
"version": "2.0.1", | "version": "2.0.1", | ||||
"resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", | "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", | ||||
@@ -11687,6 +11725,11 @@ | |||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", | "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", | ||||
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" | "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" | ||||
}, | }, | ||||
"resize-observer-polyfill": { | |||||
"version": "1.5.1", | |||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", | |||||
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" | |||||
}, | |||||
"resolve": { | "resolve": { | ||||
"version": "1.17.0", | "version": "1.17.0", | ||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", | ||||
@@ -13526,6 +13569,11 @@ | |||||
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", | "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", | ||||
"integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==" | "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==" | ||||
}, | }, | ||||
"throttle-debounce": { | |||||
"version": "1.1.0", | |||||
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", | |||||
"integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" | |||||
}, | |||||
"through": { | "through": { | ||||
"version": "2.3.8", | "version": "2.3.8", | ||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", | ||||
@@ -19,6 +19,7 @@ | |||||
"cssnano": "4.1.10", | "cssnano": "4.1.10", | ||||
"domino": "2.1.5", | "domino": "2.1.5", | ||||
"dropzone": "5.7.2", | "dropzone": "5.7.2", | ||||
"element-ui": "2.15.5", | |||||
"esdk-obs-browserjs": "3.20.7", | "esdk-obs-browserjs": "3.20.7", | ||||
"esdk-obs-nodejs": "3.20.11", | "esdk-obs-nodejs": "3.20.11", | ||||
"fast-glob": "3.2.2", | "fast-glob": "3.2.2", | ||||
@@ -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 | // GetAttachment serve attachements | ||||
func GetAttachment(ctx *context.Context) { | func GetAttachment(ctx *context.Context) { | ||||
typeCloudBrain := ctx.QueryInt("type") | typeCloudBrain := ctx.QueryInt("type") | ||||
@@ -165,16 +194,29 @@ func GetAttachment(ctx *context.Context) { | |||||
ctx.ServerError("LinkedRepository", err) | ctx.ServerError("LinkedRepository", err) | ||||
return | 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 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) | ctx.Error(http.StatusNotFound) | ||||
return | return | ||||
} | } | ||||
} else { //If we have the repository we check access | } 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 | return | ||||
} | } | ||||
if !perm.CanRead(unitType) { | 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 { | if dataSet != nil { | ||||
isPermit, err := models.GetUserDataSetPermission(dataSet, ctx.User) | isPermit, err := models.GetUserDataSetPermission(dataSet, ctx.User) | ||||
if err != nil { | if err != nil { | ||||
@@ -205,7 +241,7 @@ func GetAttachment(ctx *context.Context) { | |||||
if setting.Attachment.StoreType == storage.MinioStorageType { | if setting.Attachment.StoreType == storage.MinioStorageType { | ||||
url := "" | url := "" | ||||
if typeCloudBrain == models.TypeCloudBrainOne { | 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 { | if err != nil { | ||||
ctx.ServerError("PresignedGetURL", err) | ctx.ServerError("PresignedGetURL", err) | ||||
return | return | ||||
@@ -1,15 +1,13 @@ | |||||
package repo | package repo | ||||
import ( | import ( | ||||
"sort" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/auth" | "code.gitea.io/gitea/modules/auth" | ||||
"code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"sort" | |||||
) | ) | ||||
const ( | 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) { | if ctx.Repo.CanWrite(models.UnitTypeDatasets) { | ||||
log.Info("can write.") | |||||
return list | return list | ||||
} else { | } 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 | var publicList []*models.Attachment | ||||
for _, attach := range list { | for _, attach := range list { | ||||
if !attach.IsPrivate { | if !attach.IsPrivate { | ||||
publicList = append(publicList, attach) | publicList = append(publicList, attach) | ||||
} else { | |||||
if permission { | |||||
publicList = append(publicList, attach) | |||||
} | |||||
} | } | ||||
} | } | ||||
return publicList | return publicList | ||||
} | } | ||||
} | } | ||||
func DatasetIndex(ctx *context.Context) { | func DatasetIndex(ctx *context.Context) { | ||||
@@ -60,7 +81,7 @@ func DatasetIndex(ctx *context.Context) { | |||||
ctx.ServerError("GetDatasetAttachments", err) | ctx.ServerError("GetDatasetAttachments", err) | ||||
return | return | ||||
} | } | ||||
attachments := filterPrivateAttachments(ctx, dataset.Attachments) | |||||
attachments := newFilterPrivateAttachments(ctx, dataset.Attachments, repo) | |||||
ctx.Data["SortType"] = ctx.Query("sort") | ctx.Data["SortType"] = ctx.Query("sort") | ||||
switch ctx.Query("sort") { | switch ctx.Query("sort") { | ||||
@@ -569,10 +569,19 @@ func safeURL(address string) string { | |||||
} | } | ||||
type ContributorInfo struct { | 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 | // Home render repository home page | ||||
func Home(ctx *context.Context) { | func Home(ctx *context.Context) { | ||||
if len(ctx.Repo.Units) > 0 { | if len(ctx.Repo.Units) > 0 { | ||||
@@ -581,15 +590,31 @@ func Home(ctx *context.Context) { | |||||
if err == nil && contributors != nil { | if err == nil && contributors != nil { | ||||
var contributorInfos []*ContributorInfo | var contributorInfos []*ContributorInfo | ||||
for _, c := range contributors { | for _, c := range contributors { | ||||
// get user info from committer email | |||||
user, err := models.GetUserByEmail(c.Email) | user, err := models.GetUserByEmail(c.Email) | ||||
if err == nil { | 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 { | } 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 | ctx.Data["ContributorInfo"] = contributorInfos | ||||
@@ -1129,7 +1129,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
//secure api, | //secure api, | ||||
m.Group("/secure", func() { | m.Group("/secure", func() { | ||||
m.Post("/user", binding.Bind(structs.CreateUserOption{}), secure.CreateUser) | |||||
m.Post("/user", binding.BindIgnErr(structs.CreateUserOption{}), secure.CreateUser) | |||||
}, reqBasicAuth) | }, reqBasicAuth) | ||||
m.Group("/api/internal", func() { | m.Group("/api/internal", func() { | ||||
@@ -7,6 +7,7 @@ package secure | |||||
import ( | import ( | ||||
"net/http" | "net/http" | ||||
"strings" | |||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
@@ -75,11 +76,19 @@ func CreateUser(ctx *context.Context, form api.CreateUserOption) { | |||||
u.MustChangePassword = *form.MustChangePassword | u.MustChangePassword = *form.MustChangePassword | ||||
} | } | ||||
if strings.Contains(form.Email, " ") { | |||||
log.Error("CreateUser failed: email(%s) contains blank space", form.Email, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusBadRequest, map[string]string{ | |||||
"error_msg": "Email contains blank space", | |||||
}) | |||||
return | |||||
} | |||||
parseLoginSource(ctx, u, form.SourceID, form.LoginName) | parseLoginSource(ctx, u, form.SourceID, form.LoginName) | ||||
if ctx.Written() { | if ctx.Written() { | ||||
return | return | ||||
} | } | ||||
if !password.IsComplexEnough(form.Password) { | |||||
if !password.IsComplexEnough(form.Password) || len(form.Password) < setting.MinPasswordLength { | |||||
log.Error("CreateUser failed: PasswordComplexity", ctx.Data["MsgID"]) | log.Error("CreateUser failed: PasswordComplexity", ctx.Data["MsgID"]) | ||||
ctx.JSON(http.StatusBadRequest, map[string]string{ | ctx.JSON(http.StatusBadRequest, map[string]string{ | ||||
"error_msg": "PasswordComplexity", | "error_msg": "PasswordComplexity", | ||||
@@ -104,6 +113,29 @@ func CreateUser(ctx *context.Context, form api.CreateUserOption) { | |||||
} | } | ||||
return | 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 | |||||
} | |||||
// Send confirmation email | |||||
if setting.Service.RegisterEmailConfirm{ | |||||
mailer.SendActivateAccountMail(ctx.Locale, u) | |||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { | |||||
log.Error("Set cache(MailResendLimit) fail: %v", err) | |||||
} | |||||
} | |||||
log.Trace("Account created (%s): %s", ctx.User.Name, u.Name, ctx.Data["MsgID"]) | log.Trace("Account created (%s): %s", ctx.User.Name, u.Name, ctx.Data["MsgID"]) | ||||
// Send email notification. | // Send email notification. | ||||
@@ -1165,7 +1165,19 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo | |||||
} | } | ||||
return | 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. | // Auto-set admin for the only user. | ||||
if models.CountUsers() == 1 { | if models.CountUsers() == 1 { | ||||
@@ -1254,6 +1266,15 @@ func Activate(ctx *context.Context) { | |||||
log.Error("Error storing session: %v", err) | 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.Flash.Success(ctx.Tr("auth.account_activated")) | ||||
ctx.Redirect(setting.AppSubURL + "/") | ctx.Redirect(setting.AppSubURL + "/") | ||||
return | return | ||||
@@ -96,6 +96,18 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { | |||||
ctx.User.Location = form.Location | ctx.User.Location = form.Location | ||||
ctx.User.Language = form.Language | ctx.User.Language = form.Language | ||||
ctx.User.Description = form.Description | 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 err := models.UpdateUserSetting(ctx.User); err != nil { | ||||
if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | ||||
ctx.Flash.Error(ctx.Tr("form.email_been_used")) | ctx.Flash.Error(ctx.Tr("form.email_been_used")) | ||||
@@ -127,7 +127,7 @@ | |||||
<img src="/img/i-pic-01.svg"> | <img src="/img/i-pic-01.svg"> | ||||
</div> | </div> | ||||
<div class="content"> | <div class="content"> | ||||
<a class="ui centered header">开发要素统一管理</a> | |||||
<h3 class="ui centered header">开发要素统一管理</h3> | |||||
<div class="description"> | <div class="description"> | ||||
平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理 | 平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理 | ||||
</div> | </div> | ||||
@@ -138,7 +138,7 @@ | |||||
<img src="/img/i-pic-02.svg"> | <img src="/img/i-pic-02.svg"> | ||||
</div> | </div> | ||||
<div class="content"> | <div class="content"> | ||||
<a class="ui centered header">数据协同与共享</a> | |||||
<h3 class="ui centered header">数据协同与共享</h3> | |||||
<div class="description"> | <div class="description"> | ||||
通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型 | 通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型 | ||||
</div> | </div> | ||||
@@ -149,7 +149,7 @@ | |||||
<img src="/img/i-pic-03.svg"> | <img src="/img/i-pic-03.svg"> | ||||
</div> | </div> | ||||
<div class="content"> | <div class="content"> | ||||
<a class="ui centered header">模型管理与共享</a> | |||||
<h3 class="ui centered header">模型管理与共享</h3> | |||||
<div class="description"> | <div class="description"> | ||||
将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈 | 将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈 | ||||
</div> | </div> | ||||
@@ -160,7 +160,7 @@ | |||||
<img src="/img/i-pic-04.svg"> | <img src="/img/i-pic-04.svg"> | ||||
</div> | </div> | ||||
<div class="content"> | <div class="content"> | ||||
<a class="ui centered header">一次配置,多次使用</a> | |||||
<h3 class="ui centered header">一次配置,多次使用</h3> | |||||
<div class="description"> | <div class="description"> | ||||
提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境 | 提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境 | ||||
</div> | </div> | ||||
@@ -4,6 +4,48 @@ | |||||
font-size: 1.0em; | font-size: 1.0em; | ||||
margin-bottom: 1.0rem; | 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; | |||||
} | |||||
</style> | </style> | ||||
<div class="repository file list"> | <div class="repository file list"> | ||||
{{template "repo/header" .}} | {{template "repo/header" .}} | ||||
@@ -155,37 +197,55 @@ | |||||
</div> | </div> | ||||
<div class="ui six wide tablet four wide computer column"> | <div class="ui six wide tablet four wide computer column"> | ||||
<div id="repo-desc"> | <div id="repo-desc"> | ||||
<h4 class="ui header">简介</h4> | |||||
<h4 id="about-desc" class="ui header">简介 | |||||
<!-- <a class="edit-icon" href="javascript:void(0)"> | |||||
<i class="gray edit outline icon"></i> | |||||
</a> --> | |||||
</h4> | |||||
<p> | <p> | ||||
{{if .Repository.DescriptionHTML}} | |||||
<span class="description">{{.Repository.DescriptionHTML}}</span> | |||||
{{else}} | |||||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||||
{{end}} | |||||
<a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | |||||
{{if .Repository.DescriptionHTML}} | |||||
<span class="description" style="word-break:break-all">{{.Repository.DescriptionHTML}}</span> | |||||
{{else}} | |||||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||||
{{end}} | |||||
</p> | </p> | ||||
</div> | </div> | ||||
{{if .Repository.Website}} | |||||
<p class="ui"> | |||||
<i class="gray linkify icon"></i> | |||||
<a class="link" target="_blank" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | |||||
</p> | |||||
{{end}} | |||||
<p class="ui" id="repo-topics"> | <p class="ui" id="repo-topics"> | ||||
<i class="grey bookmark icon"></i> | <i class="grey bookmark icon"></i> | ||||
{{range .Topics}}<a class="ui repo-topic small label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} | {{range .Topics}}<a class="ui repo-topic small label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} | ||||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<a id="manage_topic">{{.i18n.Tr "repo.topic.manage_topics"}}</a>{{end}} | {{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<a id="manage_topic">{{.i18n.Tr "repo.topic.manage_topics"}}</a>{{end}} | ||||
</p> | </p> | ||||
<p class="ui"> | <p class="ui"> | ||||
<i class="grey code icon"></i> | <i class="grey code icon"></i> | ||||
{{range .LanguageStats}} | {{range .LanguageStats}} | ||||
{{.Language}} | {{.Language}} | ||||
{{end}} | {{end}} | ||||
</p> | </p> | ||||
{{if .LICENSE}} | |||||
<p class="ui"> | <p class="ui"> | ||||
<i class="grey clone icon"></i> | <i class="grey clone icon"></i> | ||||
{{if .LICENSE}} | |||||
{{.LICENSE}} | |||||
{{end}} | |||||
{{.LICENSE}} | |||||
</p> | </p> | ||||
{{end}} | |||||
<div class="ui divider"></div> | <div class="ui divider"></div> | ||||
@@ -193,17 +253,15 @@ | |||||
<h4 class="ui header"> | <h4 class="ui header"> | ||||
<strong>贡献者 ({{len .ContributorInfo}})</strong> | <strong>贡献者 ({{len .ContributorInfo}})</strong> | ||||
<div class="ui right"> | <div class="ui right"> | ||||
<a class="text grey" href="">全部 {{svg "octicon-chevron-right" 16}}</a> | |||||
<a class="membersmore text grey" href="javascript:;">全部 {{svg "octicon-chevron-right" 16}}</a> | |||||
</div> | </div> | ||||
</h4> | </h4> | ||||
<div class="ui members"> | |||||
<div class="ui members" id="contributorInfo"> | |||||
{{range .ContributorInfo}} | {{range .ContributorInfo}} | ||||
{{/*<img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.UserInfo.Name}}">{{.UserInfo.Name}}</a>*/}} | |||||
{{if .UserInfo}} | {{if .UserInfo}} | ||||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}" alt=""/></a> | |||||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}"></a> | |||||
{{else if .Email}} | {{else if .Email}} | ||||
<a href="mailto:{{.Email}}"><img class="ui avatar image" src="{{AvatarLink .Email}}" alt=""/></a> | |||||
<a href="mailto:{{.Email}}" class="circular ui button">{{.Email}}</a> | |||||
{{end}} | {{end}} | ||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
@@ -215,4 +273,12 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<script type="text/javascript"> | |||||
$(document).ready(function(){ | |||||
$(".membersmore").click(function(){ | |||||
$("#contributorInfo > a:nth-child(n+25)").show(); | |||||
}); | |||||
}); | |||||
</script> | |||||
{{template "base/footer" .}} | {{template "base/footer" .}} |
@@ -6,7 +6,7 @@ | |||||
<img class="ui centered medium image" src="{{StaticUrlPrefix}}/img/icon-500@2x.png"> | <img class="ui centered medium image" src="{{StaticUrlPrefix}}/img/icon-500@2x.png"> | ||||
<h2>{{.i18n.Tr "error500_index"}}</h2> | <h2>{{.i18n.Tr "error500_index"}}</h2> | ||||
<p>{{.i18n.Tr "error404" | Safe}}</p> | |||||
<p>{{.i18n.Tr "error500" | Safe}}</p> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -0,0 +1,144 @@ | |||||
<template> | |||||
<div> | |||||
<h4 id="about-desc" class="ui header">简介 | |||||
<a class="edit-icon" href="javascript:void(0)" @click="editClick"> | |||||
<i class="gray edit outline icon"></i> | |||||
</a> | |||||
</h4> | |||||
<edit-dialog-cmpt | |||||
:vmContext="vmContext" | |||||
dialogTitle="编辑仓库信息" | |||||
v-model="editDataDialog" | |||||
:deleteCallback="editDataFunc" | |||||
:deleteLoading ="editDataListLoading" | |||||
deleteParam = "ruleForm" | |||||
@input="initForm" | |||||
> | |||||
<div slot="title"> | |||||
</div> | |||||
<div slot="content"> | |||||
<el-form label-position="top" :model="info" :rules="rule" ref="ruleForm"> | |||||
<el-form-item label="简介" prop="desc"> | |||||
<el-input v-model="info.desc" type="textarea" :autosize="{minRows:2,maxRows:6}"></el-input> | |||||
</el-form-item> | |||||
<el-form-item label="主页" prop="index_web" > | |||||
<el-input v-model="info.index_web" placeholder="主页(eg: https://git.openi.org.cn)"></el-input> | |||||
</el-form-item> | |||||
</el-form> | |||||
</div> | |||||
</edit-dialog-cmpt> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||||
import editDialogCmpt from './basic/editDialog.vue'; | |||||
export default { | |||||
components: { | |||||
editDialogCmpt, | |||||
}, | |||||
data() { | |||||
return { | |||||
vmContext: this, | |||||
editDataDialog: false, | |||||
editDataListLoading: false, | |||||
url: '', | |||||
info: { | |||||
desc: '', | |||||
index_web: '', | |||||
repo_name_name: '', | |||||
}, | |||||
// rule1:[{min:3,max:5,message:'1',trigger:"blur"}], | |||||
rule: { | |||||
index_web: [ | |||||
{required: false, pattern: /(^$)|(^(http|https):\/\/(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).*)|(^(http|https):\/\/[a-zA-Z0-9]+([_\-\.][a-zA-Z0-9]+)*\.[a-zA-Z]{2,10}(:[0-9]{1,10})?(\?.*)?(\/.*)?$)/,message:'请输入有效的URL',tigger:['change','blur']} | |||||
] | |||||
} | |||||
}; | |||||
}, | |||||
methods: { | |||||
editClick() { | |||||
this.editDataDialog = true; | |||||
}, | |||||
getDesc() { | |||||
const el = $('span.description').text(); | |||||
this.info.desc = el; | |||||
}, | |||||
getWeb() { | |||||
const el = $('a.link').text(); | |||||
this.info.index_web = el; | |||||
}, | |||||
getRepoName() { | |||||
const el = this.url.split('/')[2]; | |||||
this.info.repo_name = el; | |||||
}, | |||||
initForm(diaolog) { | |||||
if (diaolog === false) { | |||||
console.log("--watch----------") | |||||
this.getRepoName(); | |||||
this.getDesc(); | |||||
this.getWeb(); | |||||
} | |||||
}, | |||||
editDataFunc(formName) { | |||||
this.$refs[formName].validate((valid)=>{ | |||||
if (valid) { | |||||
this.$axios({ | |||||
method: 'post', | |||||
url: this.url, | |||||
header: {'content-type': 'application/x-www-form-urlencoded'}, | |||||
data: this.qs.stringify({ | |||||
_csrf: csrf, | |||||
action: 'update', | |||||
repo_name: this.info.repo_name, | |||||
description: this.info.desc, | |||||
website: this.info.index_web | |||||
}) | |||||
}).then((res) => { | |||||
location.reload(); | |||||
this.editDataDialog = false; | |||||
}).catch((error) => { | |||||
this.editDataDialog = false; | |||||
}) | |||||
} | |||||
else { | |||||
return false; | |||||
} | |||||
}) | |||||
}, | |||||
getUrl() { | |||||
const url = `${window.location.pathname}/settings`; | |||||
this.url = url; | |||||
} | |||||
}, | |||||
mounted() { | |||||
this.getUrl(); | |||||
this.getRepoName(); | |||||
this.getDesc(); | |||||
this.getWeb(); | |||||
}, | |||||
created() { | |||||
} | |||||
}; | |||||
</script> | |||||
<style scoped> | |||||
.edit-icon{ | |||||
float: right; | |||||
font-size: 16px; | |||||
display: block; | |||||
top: -2px; | |||||
color: #8c92a4; | |||||
background-color: transparent; | |||||
} | |||||
</style> |
@@ -335,6 +335,7 @@ export default { | |||||
async function uploadMinio(url, e) { | async function uploadMinio(url, e) { | ||||
const res = await axios.put(url, e.target.result); | const res = await axios.put(url, e.target.result); | ||||
delete e.target.result | |||||
etags[currentChunk] = res.headers.etag; | etags[currentChunk] = res.headers.etag; | ||||
} | } | ||||
@@ -0,0 +1,105 @@ | |||||
<template> | |||||
<el-dialog :close-on-click-modal="!deleteLoading" v-dlg-drag :title="dialogTitle" :visible.sync="deleteDialog"> | |||||
<div class="message-box__content"> | |||||
<div class="message-box-title" > | |||||
<slot name="title"></slot> | |||||
</div> | |||||
<div class="message-box-info"> | |||||
<slot name="info"></slot> | |||||
</div> | |||||
</div> | |||||
<slot name="content"></slot> | |||||
<div slot="footer" class="dialog-footer"> | |||||
<el-button @click="deleteDialog = false">{{"取消"}}</el-button> | |||||
<el-button type="primary" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</el-button> | |||||
</div> | |||||
</el-dialog> | |||||
</template> | |||||
<script type="text/javascript"> | |||||
export default { | |||||
data() { | |||||
return { | |||||
deleteDialog: false, | |||||
}; | |||||
}, | |||||
props: { | |||||
vmContext: { | |||||
type: Object, | |||||
default() { | |||||
return {}; | |||||
} | |||||
}, | |||||
dialogTitle: { | |||||
type: String, | |||||
default: '', | |||||
}, | |||||
deleteLoading: { | |||||
type: Boolean, | |||||
default: false, | |||||
}, | |||||
deleteCallback: { | |||||
type: Function, | |||||
default() { | |||||
return () => {}; | |||||
} | |||||
}, | |||||
deleteParam: { | |||||
type: String, | |||||
default: '' | |||||
}, | |||||
value: { | |||||
type: Boolean, | |||||
default: false, | |||||
} | |||||
}, | |||||
computed: { | |||||
}, | |||||
watch: { | |||||
deleteDialog() { | |||||
this.$emit('input', this.deleteDialog); | |||||
}, | |||||
value() { | |||||
this.deleteDialog = this.value; | |||||
}, | |||||
}, | |||||
created() { | |||||
this.deleteDialog = this.value; | |||||
} | |||||
}; | |||||
</script> | |||||
<style scoped> | |||||
.el-message-box__content .icon{float:left;} | |||||
.message-box__content{} | |||||
.message-box__content .icon{float:left;margin-right:20px;} | |||||
.message-box__content .message-box-title{font-size:16px;padding:2px 0;color:#333;} | |||||
.message-box__content .message-box-p{font-size:16px;padding:20px 0;color:#333;} | |||||
.message-box__content .message-box-info{color:#999;padding:2px 0;} | |||||
.dialog-footer,.el-message-box__btns{text-align:center;} | |||||
/deep/ .el-dialog__header { | |||||
background: #0067b3; | |||||
padding: 12px 30px; | |||||
line-height: 25px;} | |||||
/deep/ .el-dialog__title { | |||||
font-family: PingFangSC-Regular; | |||||
font-size: 18px; | |||||
color: #fff; | |||||
font-weight: 200; | |||||
line-height: 25px; | |||||
height: 25px; | |||||
} | |||||
/deep/ .el-dialog__footer { | |||||
background: #eff3f9; | |||||
padding: 20px 30px; | |||||
} | |||||
/deep/ .el-dialog{ | |||||
width: 40%; | |||||
} | |||||
</style> |
@@ -6,6 +6,10 @@ import './publicpath.js'; | |||||
import './polyfills.js'; | import './polyfills.js'; | ||||
import Vue from 'vue'; | import Vue from 'vue'; | ||||
import ElementUI from 'element-ui'; | |||||
import 'element-ui/lib/theme-chalk/index.css'; | |||||
import axios from 'axios'; | |||||
import qs from 'qs'; | |||||
import 'jquery.are-you-sure'; | import 'jquery.are-you-sure'; | ||||
import './vendor/semanticdropdown.js'; | import './vendor/semanticdropdown.js'; | ||||
import {svg} from './utils.js'; | import {svg} from './utils.js'; | ||||
@@ -29,8 +33,12 @@ import { | |||||
} from './features/notification.js'; | } from './features/notification.js'; | ||||
import {createCodeEditor} from './features/codeeditor.js'; | import {createCodeEditor} from './features/codeeditor.js'; | ||||
import MinioUploader from './components/MinioUploader.vue'; | import MinioUploader from './components/MinioUploader.vue'; | ||||
import ObsUploader from './components/ObsUploader.vue' | |||||
import ObsUploader from './components/ObsUploader.vue'; | |||||
import EditAboutInfo from './components/EditAboutInfo.vue'; | |||||
Vue.use(ElementUI); | |||||
Vue.prototype.$axios = axios; | |||||
Vue.prototype.qs = qs; | |||||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | ||||
function htmlEncode(text) { | function htmlEncode(text) { | ||||
@@ -2957,6 +2965,7 @@ $(document).ready(async () => { | |||||
initVueApp(); | initVueApp(); | ||||
initVueUploader(); | initVueUploader(); | ||||
initObsUploader(); | initObsUploader(); | ||||
initVueEditAbout(); | |||||
initTeamSettings(); | initTeamSettings(); | ||||
initCtrlEnterSubmit(); | initCtrlEnterSubmit(); | ||||
initNavbarContentToggle(); | initNavbarContentToggle(); | ||||
@@ -3642,6 +3651,19 @@ function initVueUploader() { | |||||
}); | }); | ||||
} | } | ||||
function initVueEditAbout() { | |||||
const el = document.getElementById('about-desc'); | |||||
console.log(el) | |||||
if (!el) { | |||||
return; | |||||
} | |||||
new Vue({ | |||||
el: '#about-desc', | |||||
render: h => h(EditAboutInfo) | |||||
}); | |||||
} | |||||
// 新增 | // 新增 | ||||
function initObsUploader() { | function initObsUploader() { | ||||
const el = document.getElementById('obsUploader'); | const el = document.getElementById('obsUploader'); | ||||
@@ -2685,7 +2685,7 @@ tbody.commit-list { | |||||
width: 1127px; | width: 1127px; | ||||
} | } | ||||
th .message-wrapper { | th .message-wrapper { | ||||
max-width: 680px; | |||||
max-width: 510px; | |||||
} | } | ||||
} | } | ||||