| @@ -11,7 +11,7 @@ watch_dirs = [ | |||
| "$WORKDIR/models", | |||
| "$WORKDIR/cmd", | |||
| "$WORKDIR/options", | |||
| "$WORKDIR/web_src", | |||
| "$WORKDIR/public", | |||
| ] # Directories to watch | |||
| watch_exts = [".go", ".ini", ".less"] # Extensions to watch | |||
| env_files = [] # Load env vars from files | |||
| @@ -4,13 +4,27 @@ import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/builder" | |||
| ) | |||
| // Issue represents an issue or pull request of repository. | |||
| const ( | |||
| DatasetStatusPrivate int = iota | |||
| DatasetStatusPublic | |||
| DatasetStatusDeleted | |||
| ) | |||
| type DatasetList []*Dataset | |||
| type SearchDatasetOptions struct { | |||
| ListOptions | |||
| Keyword string | |||
| OwnerID int64 | |||
| IsPublic bool | |||
| } | |||
| type Dataset struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Title string `xorm:"INDEX NOT NULL"` | |||
| Status int32 `xorm:"INDEX"` | |||
| Status int32 `xorm:"INDEX"` // normal_private: 0, pulbic: 1, is_delete: 2 | |||
| Category string | |||
| Description string `xorm:"TEXT"` | |||
| DownloadTimes int64 | |||
| @@ -70,3 +84,48 @@ func UpdateDataset(ctx DBContext, rel *Dataset) error { | |||
| _, err := ctx.e.ID(rel.ID).AllCols().Update(rel) | |||
| return err | |||
| } | |||
| func SearchDataset(opts *SearchDatasetOptions) (DatasetList, int64, error) { | |||
| cond := SearchDatasetCondition(opts) | |||
| return SearchDatasetByCondition(opts, cond) | |||
| } | |||
| func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||
| var cond = builder.NewCond() | |||
| cond = cond.And(builder.Eq{"user_id": opts.OwnerID}) | |||
| if opts.IsPublic { | |||
| cond = cond.And(builder.Eq{"status": DatasetStatusPublic}) | |||
| } else { | |||
| cond = cond.And(builder.Neq{"status": DatasetStatusDeleted}) | |||
| } | |||
| return cond | |||
| } | |||
| func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (DatasetList, int64, error) { | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| var err error | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| // count, err := sess.Where(cond).Count(new(DatasetList)) | |||
| // if err != nil { | |||
| // return nil, 0, fmt.Errorf("Count: %v", err) | |||
| // } | |||
| repos := make(DatasetList, 0, opts.PageSize) | |||
| sess.Where(cond) | |||
| if opts.PageSize > 0 { | |||
| sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
| } | |||
| if err = sess.Find(&repos); err != nil { | |||
| return nil, 0, fmt.Errorf("Dataset: %v", err) | |||
| } | |||
| return repos, 0, nil | |||
| } | |||
| @@ -64,3 +64,7 @@ func (l *LocalStorage) Delete(path string) error { | |||
| p := filepath.Join(l.dir, path) | |||
| return os.Remove(p) | |||
| } | |||
| func (l *LocalStorage) PresignedGetURL(path string, fileName string) (string,error) { | |||
| return "",nil | |||
| } | |||
| @@ -6,8 +6,10 @@ package storage | |||
| import ( | |||
| "io" | |||
| "net/url" | |||
| "path" | |||
| "strings" | |||
| "time" | |||
| "github.com/minio/minio-go" | |||
| ) | |||
| @@ -16,6 +18,8 @@ var ( | |||
| _ ObjectStorage = &MinioStorage{} | |||
| ) | |||
| const PRESIGNED_URL_EXPIRE_TIME = time.Hour * 24 * 7 | |||
| // MinioStorage returns a minio bucket storage | |||
| type MinioStorage struct { | |||
| client *minio.Client | |||
| @@ -68,3 +72,18 @@ func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) { | |||
| func (m *MinioStorage) Delete(path string) error { | |||
| return m.client.RemoveObject(m.bucket, m.buildMinioPath(path)) | |||
| } | |||
| //Get Presigned URL | |||
| func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string,error) { | |||
| // Set request parameters for content-disposition. | |||
| reqParams := make(url.Values) | |||
| reqParams.Set("response-content-disposition", "attachment; filename=\"" + fileName + "\"") | |||
| var preURL *url.URL | |||
| preURL,err := m.client.PresignedGetObject(m.bucket, m.buildMinioPath(path), PRESIGNED_URL_EXPIRE_TIME, reqParams) | |||
| if err != nil { | |||
| return "",err | |||
| } | |||
| return preURL.String(),nil | |||
| } | |||
| @@ -16,6 +16,7 @@ type ObjectStorage interface { | |||
| Save(path string, r io.Reader) (int64, error) | |||
| Open(path string) (io.ReadCloser, error) | |||
| Delete(path string) error | |||
| PresignedGetURL(path string, fileName string) (string, error) | |||
| } | |||
| // Copy copys a file from source ObjectStorage to dest ObjectStorage | |||
| @@ -15,7 +15,40 @@ const ( | |||
| tplCreate base.TplName = "datasets/create" | |||
| ) | |||
| type ListOptions struct { | |||
| PageSize int | |||
| Page int // start from 1 | |||
| } | |||
| func MyList(ctx *context.Context) { | |||
| ctxUser := ctx.User | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| datasetSearchOptions := &models.SearchDatasetOptions{ | |||
| OwnerID: ctxUser.ID, | |||
| } | |||
| var ( | |||
| datasets []*models.Dataset | |||
| count int64 | |||
| err error | |||
| ) | |||
| datasets, count, err = models.SearchDataset(datasetSearchOptions) | |||
| if err != nil { | |||
| ctx.ServerError("SearchDatasets", err) | |||
| return | |||
| } | |||
| // pager := context.NewPagination(int(count), opts.PageSize, page, 5) | |||
| // pager.SetDefaultParams(ctx) | |||
| // pager.AddParam(ctx, "topic", "TopicOnly") | |||
| // ctx.Data["Page"] = pager | |||
| ctx.Data["datasets"] = datasets | |||
| ctx.Data["datasetsCount"] = count | |||
| log.Debug("[dataset] mylist...\n") | |||
| ctx.HTML(200, tplDataSet) | |||
| } | |||
| @@ -5,6 +5,7 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/storage" | |||
| "fmt" | |||
| "net/http" | |||
| "strings" | |||
| @@ -13,7 +14,6 @@ import ( | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/storage" | |||
| "code.gitea.io/gitea/modules/upload" | |||
| ) | |||
| @@ -128,6 +128,7 @@ func GetAttachment(ctx *context.Context) { | |||
| } | |||
| //If we have matched and access to release or issue | |||
| /* | |||
| fr, err := storage.Attachments.Open(attach.RelativePath()) | |||
| if err != nil { | |||
| ctx.ServerError("Open", err) | |||
| @@ -135,13 +136,29 @@ func GetAttachment(ctx *context.Context) { | |||
| } | |||
| defer fr.Close() | |||
| */ | |||
| url, err := storage.Attachments.PresignedGetURL(attach.RelativePath(), attach.Name) | |||
| if err != nil { | |||
| ctx.ServerError("PresignedGetURL", err) | |||
| return | |||
| } | |||
| if err := attach.IncreaseDownloadCount(); err != nil { | |||
| ctx.ServerError("Update", err) | |||
| return | |||
| } | |||
| ctx.JSON(200, map[string]string{ | |||
| "name": attach.Name, | |||
| "url": url, | |||
| }) | |||
| /* | |||
| if err = ServeData(ctx, attach.Name, fr); err != nil { | |||
| ctx.ServerError("ServeData", err) | |||
| return | |||
| } | |||
| */ | |||
| } | |||
| @@ -1,4 +1,21 @@ | |||
| <div class="ui repository list"> | |||
| {{range .datasets}} | |||
| <div class="item"> | |||
| <div class="ui header"> | |||
| <a class="name" href=""> | |||
| {{.Title}} | |||
| </a> | |||
| <div class="ui right metas"> | |||
| <span class="text grey">{{svg "octicon-flame" 16}} 24</span> | |||
| </div> | |||
| </div> | |||
| <div class="description"> | |||
| <a><div class="ui small label topic">{{.Description}}</div></a> | |||
| <p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}</p> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| <div class="item"> | |||
| <div class="ui header"> | |||
| <a class="name" href="{{.Link}}"> | |||