@@ -46,6 +46,7 @@ type Attachment struct { | |||||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | CreatedUnix timeutil.TimeStamp `xorm:"created"` | ||||
FileChunk *FileChunk `xorm:"-"` | FileChunk *FileChunk `xorm:"-"` | ||||
CanDel bool `xorm:"-"` | |||||
} | } | ||||
type AttachmentUsername struct { | type AttachmentUsername struct { | ||||
@@ -437,3 +438,29 @@ func getModelArtsUserAttachments(e Engine, userID int64) ([]*AttachmentUsername, | |||||
func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) { | func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) { | ||||
return getModelArtsUserAttachments(x, userID) | return getModelArtsUserAttachments(x, userID) | ||||
} | } | ||||
func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool { | |||||
if !isSigned { | |||||
return false | |||||
} | |||||
dataset, err := GetDatasetByID(attach.DatasetID) | |||||
if err != nil { | |||||
log.Error("GetDatasetByID failed:%v", err.Error()) | |||||
return false | |||||
} | |||||
repo, _ := GetRepositoryByID(dataset.RepoID) | |||||
if err != nil { | |||||
log.Error("GetRepositoryByID failed:%v", err.Error()) | |||||
return false | |||||
} | |||||
permission, _ := GetUserRepoPermission(repo, user) | |||||
if err != nil { | |||||
log.Error("GetUserRepoPermission failed:%v", err.Error()) | |||||
return false | |||||
} | |||||
if user.ID == attach.UploaderID || user.IsAdmin || permission.AccessMode >= AccessModeAdmin { | |||||
return true | |||||
} | |||||
return false | |||||
} |
@@ -196,11 +196,11 @@ func (s datasetMetaSearch) Less(i, j int) bool { | |||||
return s.ID[i] < s.ID[j] | return s.ID[i] < s.ID[j] | ||||
} | } | ||||
func GetDatasetAttachments(typeCloudBrain int, rels ...*Dataset) (err error) { | |||||
return getDatasetAttachments(x, typeCloudBrain, rels...) | |||||
func GetDatasetAttachments(typeCloudBrain int, isSigned bool, user *User, rels ...*Dataset) (err error) { | |||||
return getDatasetAttachments(x, typeCloudBrain, isSigned, user, rels...) | |||||
} | } | ||||
func getDatasetAttachments(e Engine, typeCloudBrain int, rels ...*Dataset) (err error) { | |||||
func getDatasetAttachments(e Engine, typeCloudBrain int, isSigned bool, user *User, rels ...*Dataset) (err error) { | |||||
if len(rels) == 0 { | if len(rels) == 0 { | ||||
return | return | ||||
} | } | ||||
@@ -243,6 +243,7 @@ func getDatasetAttachments(e Engine, typeCloudBrain int, rels ...*Dataset) (err | |||||
return err | return err | ||||
} | } | ||||
attachment.FileChunk = fileChunks[0] | attachment.FileChunk = fileChunks[0] | ||||
attachment.CanDel = CanDelAttachment(isSigned, user, attachment) | |||||
sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment) | sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment) | ||||
} | } | ||||
@@ -128,7 +128,9 @@ func DeleteAttachment(ctx *context.Context) { | |||||
ctx.Error(400, err.Error()) | ctx.Error(400, err.Error()) | ||||
return | return | ||||
} | } | ||||
if !ctx.IsSigned || (ctx.User.ID != attach.UploaderID) { | |||||
//issue 214: mod del-dataset permission | |||||
if !models.CanDelAttachment(ctx.IsSigned, ctx.User, attach) { | |||||
ctx.Error(403) | ctx.Error(403) | ||||
return | return | ||||
} | } | ||||
@@ -146,7 +148,7 @@ func DeleteAttachment(ctx *context.Context) { | |||||
_, err = models.DeleteFileChunkById(attach.UUID) | _, err = models.DeleteFileChunkById(attach.UUID) | ||||
if err != nil { | if err != nil { | ||||
ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err)) | |||||
ctx.Error(500, fmt.Sprintf("DeleteFileChunkById: %v", err)) | |||||
return | return | ||||
} | } | ||||
ctx.JSON(200, map[string]string{ | ctx.JSON(200, map[string]string{ | ||||
@@ -76,7 +76,7 @@ func QueryDataSet(ctx *context.Context) []*models.Attachment { | |||||
ctx.NotFound("type error", nil) | ctx.NotFound("type error", nil) | ||||
return nil | return nil | ||||
} | } | ||||
err = models.GetDatasetAttachments(ctx.QueryInt("type"), dataset) | |||||
err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetDatasetAttachments", err) | ctx.ServerError("GetDatasetAttachments", err) | ||||
return nil | return nil | ||||
@@ -120,7 +120,7 @@ func DatasetIndex(ctx *context.Context) { | |||||
ctx.NotFound("type error", nil) | ctx.NotFound("type error", nil) | ||||
return | return | ||||
} | } | ||||
err = models.GetDatasetAttachments(ctx.QueryInt("type"), dataset) | |||||
err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetDatasetAttachments", err) | ctx.ServerError("GetDatasetAttachments", err) | ||||
return | return | ||||
@@ -39,6 +39,7 @@ | |||||
</style> | </style> | ||||
<div class="ui secondary pointing tabular top attached borderless menu navbar"> | <div class="ui secondary pointing tabular top attached borderless menu navbar"> | ||||
{{if .PageIsExplore}} | |||||
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?sort=hot&q={{$.Keyword}}&tab={{$.TabName}}"> | <a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?sort=hot&q={{$.Keyword}}&tab={{$.TabName}}"> | ||||
<svg class="svg octicon-repo" width="16" height="16" aria-hidden="true"> | <svg class="svg octicon-repo" width="16" height="16" aria-hidden="true"> | ||||
<use xlink:href="#octicon-repo" /> | <use xlink:href="#octicon-repo" /> | ||||
@@ -51,7 +52,7 @@ | |||||
</svg> | </svg> | ||||
活跃{{.i18n.Tr "explore.repos"}} | 活跃{{.i18n.Tr "explore.repos"}} | ||||
</a> | </a> | ||||
{{end}} | |||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}"> | <a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}"> | ||||
<svg class="svg octicon-organization" width="16" height="16" aria-hidden="true"> | <svg class="svg octicon-organization" width="16" height="16" aria-hidden="true"> | ||||
<use xlink:href="#octicon-organization" /> | <use xlink:href="#octicon-organization" /> | ||||
@@ -24,22 +24,6 @@ | |||||
<td class="four wide"> 状态 </td> | <td class="four wide"> 状态 </td> | ||||
<td> {{.State}} </td> | <td> {{.State}} </td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td> 开始时间 </td> | |||||
<td>{{.StartTime}}</td> | |||||
</tr> | |||||
<tr> | |||||
<td> 结束时间 </td> | |||||
<td>{{.FinishedTime}}</td> | |||||
</tr> | |||||
<tr> | |||||
<td> ExitCode </td> | |||||
<td>{{.ExitCode}}</td> | |||||
</tr> | |||||
<tr> | |||||
<td> 退出信息 </td> | |||||
<td>{{.ExitDiagnostics| nl2br}}</td> | |||||
</tr> | |||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
{{end}} | {{end}} | ||||
@@ -73,7 +57,7 @@ | |||||
</thead> | </thead> | ||||
<tbody> | <tbody> | ||||
<tr> | <tr> | ||||
<td class="four wide"> 状态 </td> | |||||
<td class="four wide"> 平台 </td> | |||||
<td> {{.Platform}} </td> | <td> {{.Platform}} </td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -31,7 +31,7 @@ | |||||
</div> | </div> | ||||
{{end}} | {{end}} | ||||
{{if $.Permission.CanWrite $.UnitTypeDatasets}} | {{if $.Permission.CanWrite $.UnitTypeDatasets}} | ||||
{{if $.Repository.IsPrivate}} | |||||
{{if (not .CanDel) or $.Repository.IsPrivate}} | |||||
<div class="two wide column"> | <div class="two wide column"> | ||||
<a class="ui button mini" disabled='true' data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}'>{{$.i18n.Tr "dataset.private"}}</a> | <a class="ui button mini" disabled='true' data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}'>{{$.i18n.Tr "dataset.private"}}</a> | ||||
</div> | </div> | ||||
@@ -45,7 +45,7 @@ | |||||
</div> | </div> | ||||
{{end}} | {{end}} | ||||
<div class="two wide column right aligned"> | |||||
<div class="two wide column right aligned" style="{{if not .CanDel}}visibility: hidden;{{end}}"> | |||||
<a class="ui red button mini" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | <a class="ui red button mini" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | ||||
</div> | </div> | ||||
{{end}} | {{end}} | ||||