#4850 数据集目录预览功能合入

Merged
ychao_1983 merged 81 commits from zouap_dev into V20231102 6 months ago
  1. +183
    -1
      custom/public/img/logo-footer.svg
  2. +0
    -1
      models/repo_permission.go
  3. +11
    -0
      models/unit.go
  4. +177
    -37
      modules/storage/minio_ext.go
  5. +148
    -1
      modules/storage/obs.go
  6. +6
    -0
      options/locale/locale_en-US.ini
  7. +5
    -0
      options/locale/locale_zh-CN.ini
  8. +293
    -721
      public/self/dataset_preview.js
  9. +7
    -3
      routers/api/v1/api.go
  10. +12
    -0
      routers/api/v1/repo/attachments.go
  11. +33
    -13
      routers/org/teams.go
  12. +368
    -0
      routers/repo/attachment_dir.go
  13. +1
    -0
      routers/repo/dir.go
  14. +83
    -207
      templates/repo/datasets/dirs/dir_preview.tmpl
  15. +18
    -12
      templates/repo/datasets/dirs/index.tmpl

+ 183
- 1
custom/public/img/logo-footer.svg
File diff suppressed because it is too large
View File


+ 0
- 1
models/repo_permission.go View File

@@ -188,7 +188,6 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
}

perm.Units = repo.Units

// anonymous visit public repo
if user == nil {
perm.AccessMode = AccessModeRead


+ 11
- 0
models/unit.go View File

@@ -60,6 +60,8 @@ func (u UnitType) String() string {
return "UnitTypeBlockChain"
case UnitTypeModelManage:
return "UnitTypeModelManage"
case UnitTypeHPC:
return "UnitTypeHPC"
}
return fmt.Sprintf("Unknown UnitType %d", u)
}
@@ -297,6 +299,14 @@ var (
8,
}

UnitHPC = Unit{
UnitTypeHPC,
"repo.hpc",
"/supercompute",
"repo.hpc.desc",
9,
}

// Units contains all the units
Units = map[UnitType]Unit{
UnitTypeCode: UnitCode,
@@ -310,6 +320,7 @@ var (
UnitTypeCloudBrain: UnitCloudBrain,
UnitTypeBlockChain: UnitBlockChain,
UnitTypeModelManage: UnitModelManage,
UnitTypeHPC: UnitHPC,
}
)



+ 177
- 37
modules/storage/minio_ext.go View File

@@ -175,53 +175,62 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel
Prefix += "/"
}
log.Info("bucket=" + bucket + " Prefix=" + Prefix)
output, err := core.ListObjects(bucket, Prefix, "", "", 1000)
marker := ""
fileInfos := make([]FileInfo, 0)
prefixLen := len(Prefix)
fileMap := make(map[string]bool, 0)
if err == nil {
for _, val := range output.Contents {

log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileName = val.Key[prefixLen:]
log.Info("fileName =" + fileName)
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
index := 1
for {
output, err := core.ListObjects(bucket, Prefix, marker, "", 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
for _, val := range output.Contents {
log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileName = val.Key[prefixLen:]
log.Info("fileName =" + fileName)
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
if output.IsTruncated {
marker = output.NextMarker
} else {
isDir = false
break
}

fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
}
return fileInfos, err
} else {
} else {

log.Error("Message:%s", err.Error())
log.Error("Message:%s", err.Error())

return nil, err
return nil, err
}
}
return fileInfos, err
}

func MinioGetFilesSize(bucketName string, Files []string) int64 {
@@ -422,3 +431,134 @@ func MinioCheckAndGetFileSize(srcBucket string, key string) (bool, int64) {
}
return true, meta.Size
}

func GetDirsListMinio(bucket string, prefixRootPath string, prefix string, dirLevel int) ([]string, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, err
}
minioPrefix := prefixRootPath + prefix
if !strings.HasSuffix(minioPrefix, "/") {
minioPrefix += "/"
}
prefixLen := len(minioPrefix)
delimiter := ""
marker := ""
index := 1
fileMap := make(map[string]bool, 0)
log.Info("buckent=" + bucket + " minioPrefix=" + minioPrefix)
for {
output, err := core.ListObjects(bucket, minioPrefix, marker, delimiter, 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
for _, val := range output.Contents {
fileName := val.Key[prefixLen:]
files := strings.Split(fileName, "/")
currentLevel := 0
for {
if currentLevel >= dirLevel || currentLevel >= (len(files)-1) {
break
}
path := getPathFromPathArrays(files, currentLevel)
if !fileMap[path] {
fileMap[path] = true
}
currentLevel = currentLevel + 1
}
}
if output.IsTruncated {
marker = output.NextMarker
} else {
break
}
} else {
log.Info("list error." + err.Error())
return nil, err
}
}
result := make([]string, 0)
for k, _ := range fileMap {
result = append(result, k)
}
return result, nil
}

func GetDirsSomeFileMinio(bucket string, prefixRootPath string, relativePath string, marker string, pageSize int) ([]FileInfo, string, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, "", err
}

Prefix := prefixRootPath + relativePath
if !strings.HasSuffix(Prefix, "/") {
Prefix += "/"
}
log.Info("bucket=" + bucket + " Prefix=" + Prefix)
fileInfos := make([]FileInfo, 0)

fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := core.ListObjects(bucket, Prefix, marker, "", 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
isBreak := false
for _, val := range output.Contents {
//log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileNameRune := []rune(val.Key)
prefixRune := []rune(Prefix)

fileName = string(fileNameRune[len(prefixRune):])
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
if len(fileInfos) >= pageSize {
marker = val.Key
isBreak = true
break
}
}
if isBreak {
break
}
if output.IsTruncated {
marker = output.NextMarker
} else {
marker = ""
break
}
} else {
log.Error("Message:%s", err.Error())
return nil, "", err
}
}
return fileInfos, marker, err
}

+ 148
- 1
modules/storage/obs.go View File

@@ -742,7 +742,7 @@ func PutStringToObs(bucket, key string, fileContent string) error {
}

func PutReaderToObs(bucket, key string, reader io.Reader) error {
log.Info("PutStringToObs bucket=" + bucket + " key=" + key)
log.Info("PutReaderToObs bucket=" + bucket + " key=" + key)
input := &obs.PutObjectInput{}
input.Bucket = bucket
input.Key = key
@@ -755,3 +755,150 @@ func PutReaderToObs(bucket, key string, reader io.Reader) error {
}
return err
}

func GetDirsList(bucket string, prefixRootPath string, prefix string, dirLevel int) ([]string, error) {
input := &obs.ListObjectsInput{}
input.Bucket = bucket
input.Prefix = prefixRootPath + prefix
if !strings.HasSuffix(input.Prefix, "/") {
input.Prefix += "/"
}
prefixLen := len(input.Prefix)
fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := ObsCli.ListObjects(input)
if err == nil {
log.Info("Page:%d\n input.Prefix=v%", index, input.Prefix)
log.Info("input.Prefix=" + input.Prefix)
index++
for _, val := range output.Contents {
fileName := val.Key[prefixLen:]
files := strings.Split(fileName, "/")
currentLevel := 0
for {
if currentLevel >= dirLevel || currentLevel >= (len(files)-1) {
break
}
path := getPathFromPathArrays(files, currentLevel)
if !fileMap[path] {
fileMap[path] = true
}
currentLevel = currentLevel + 1
}
}
if output.IsTruncated {
input.Marker = output.NextMarker
} else {
break
}
} else {
if obsError, ok := err.(obs.ObsError); ok {
log.Error("Code:%s, Message:%s", obsError.Code, obsError.Message)
}
return nil, err
}
}
result := make([]string, 0)
for k, _ := range fileMap {
result = append(result, k)
}
return result, nil
}

func getPathFromPathArrays(files []string, currentLevel int) string {
from := 0
re := ""
for {
re += files[from]
if from >= currentLevel {
break
}
from = from + 1
re += "/"
}
return re
}

func GetDirsSomeFile(bucket string, prefixRootPath string, prefix string, marker string, pageSize int) ([]FileInfo, string, error) {
input := &obs.ListObjectsInput{}
input.Bucket = bucket
input.Prefix = prefixRootPath + prefix
if !strings.HasSuffix(input.Prefix, "/") {
input.Prefix += "/"
}
input.Marker = marker
fileInfos := make([]FileInfo, 0)
//prefixLen := len(input.Prefix)
fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := ObsCli.ListObjects(input)
if err == nil {
log.Info("Page:%d input.Prefix=v%", index, input.Prefix)
log.Info("input.Prefix=" + input.Prefix)
index++
isBreak := false
for _, val := range output.Contents {
var isDir bool
var fileName string
//log.Info("val.Key=" + val.Key)
if val.Key == input.Prefix {
continue
}
fileNameRune := []rune(val.Key)
prefixRune := []rune(input.Prefix)

fileName = string(fileNameRune[len(prefixRune):])
//log.Info("fileName=" + fileName)
//val.Key[prefixLen:]
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := prefix
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
if len(fileInfos) >= pageSize {
marker = val.Key
log.Info("marker 1= " + marker)
isBreak = true
break
}
}
if isBreak {
break
}
if output.IsTruncated {
input.Marker = output.NextMarker
marker = output.NextMarker
log.Info("marker 2= " + marker)
} else {
marker = ""
log.Info("marker 3= " + marker)
break
}
} else {
if obsError, ok := err.(obs.ObsError); ok {
log.Error("Code:%s, Message:%s", obsError.Code, obsError.Message)
}
return nil, "", err
}
}
return fileInfos, marker, nil
}

+ 6
- 0
options/locale/locale_en-US.ini View File

@@ -864,6 +864,11 @@ download_copy=Copy URL
create_dataset_fail=Failed to create dataset.
query_dataset_fail=Failed to query dataset.
edit_attachment_fail=Failed to update description.
file_list=File list
file_not_support_preview=File does not support preview
please_select_file_preview=Please select a file for preview
see_more=See more

show_dataset= Dataset
edit_dataset= Edit Dataset
update_dataset= Update Dataset
@@ -1002,6 +1007,7 @@ go_new_dataset= to create the dataset
export_tips = Only <span style="color:red">zip/tar.gz</span> type result file export is supported, and the exported file can finally be viewed on the Datasets tab of the current project.

[repo]
attachmentfilesizetobig=The file size exceeds 2000 lines or 2MB, and preview is not supported.
owner = Owner
repo_name = Repository Name
repo_name_helper = Good repository names use short, memorable and unique keywords.


+ 5
- 0
options/locale/locale_zh-CN.ini View File

@@ -864,6 +864,10 @@ create_dataset=创建数据集
create_dataset_fail=创建数据集失败。
query_dataset_fail=查询数据集失败。
edit_attachment_fail=修改描述失败。
file_list=文件列表
file_not_support_preview=文件暂不支持预览
please_select_file_preview=请选择文件进行预览
see_more=查看更多

reference_dataset_fail=关联数据集失败,请稍后再试。
cancel_reference_dataset_fail=取消关联数据集失败,请稍后再试。
@@ -1007,6 +1011,7 @@ go_new_dataset=去创建数据集
export_tips = 仅支持 <span style="color:red">zip/tar.gz</span> 类型的结果文件导出,导出的文件最终可以在当前项目的数据集页签下查看。

[repo]
attachmentfilesizetobig=文件大小超过2000行或者超过2MB,不支持预览。
owner=拥有者
repo_name=项目名称
repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。


+ 293
- 721
public/self/dataset_preview.js View File

@@ -1,754 +1,326 @@
var img=new Image();

var ip = getIp();



var token = getCookie("_csrf");

canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
// canvas.width = document.getElementById("myCanvas").offsetWidth;
// canvas.height = document.getElementById("myCanvas").offsetWidth/1280*720;

canvas.width = document.getElementById("win_canvas").offsetWidth;
canvas.height = document.getElementById("win_canvas").offsetHeight;




var color_dict = {"car":"#0099CC", "person":"#FF99CC","point":"#00cc00","pointselected":"red"};
var color_person = {"0":"#13c90c","1":"#fc0707","2":"#FF99CC","3":"#fceb07"};

var rects=[];
var masks=[];
var pointShapes =[];

var fileindex =0;
var lastindex=false;
var labeltastresult;

var pageSize = 12;
var tableData;
var tablePageData;
var dataset_id = $('#hide_uuidid').val();
var dbdatasetid = dataset_id;
var textContent;
var labelInfo;
(function () {
function DatasetPreview() {
this.datasetData = DATASET_DATA;
this.supportImgReg = /(\.jpg|\.jpeg|\.png|\.gif|\.bmp)$/i;
this.supportTxtReg = /(\.txt|\.xml|\.html|\.json|\.py|\.sh|\.md|\.csv|\.log|\.js|\.css|\.ipynb)$/i;
this.data = {
filePath: [{ path: '', name: this.datasetData.path[0], ParenDir: '', marker: '' }],
dirMarkerChildrenMap: {},
fileContentMap: {},
currentPage: '',
};
this.currentFileList = [];
this.currentFile = '';
this.pageSize = 100;
this.getPathChildren();
this.eventInit();
}

page(0,pageSize);
DatasetPreview.prototype.renderFilePath = function () {
var container = $('#file_path_container').empty();
var filePath = this.data.filePath;
for (let i = 0, iLen = filePath.length; i < iLen; i++) {
var path = filePath[i];
var pathEle;
if (i == iLen - 1) {
pathEle = $(`<div>
<span class="" href="javascript:;">${path.name}</span><div class="divider"> / </div>
</div>`);
} else {
pathEle = $(`<div>
<a class="section" href="javascript:;">${path.name}</a><div class="divider"> / </div>
</div>`);
}
pathEle.data('data', path);
container.append(pathEle);
}
};

DatasetPreview.prototype.prevDirs = function () {
this.data.filePath.pop();
this.getPathChildren();
};

function getCookie(name)
{
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
}
DatasetPreview.prototype.nextDirs = function (pathObj) {
this.data.filePath.push({
...pathObj,
path: pathObj.FileName,
name: pathObj.FileName,
});
this.getPathChildren();
};

function list(current,pageSize){
$.ajax({
type:"GET",
url:ip + "/gitea-dateset-item-page",
headers: {
authorization:token,
},
dataType:"json",
data:{
'datasetId':dbdatasetid,
'startPage':current,
'pageSize':pageSize},
async:false,
success:function(json){
tablePageData = json;
tableData = json.data;
labeltastresult = tableData;
fileindex=0;
if(lastindex){
fileindex = pageSize - 1;
}
},
error:function(response) {
DatasetPreview.prototype.getPathChildrenMore = function () {
var self = this;
var lastDir = this.data.filePath[this.data.filePath.length - 1];
var path = this.data.filePath.map((item) => item.path).join('/');
if (!lastDir) return;
$('#myCanvas_div .tabpannel.ui.form').addClass('loading');
$.ajax({
type: "get",
url: `/api/v1/attachments/get_dir`,
dataType: "json",
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
marker: lastDir.marker,
pageSize: this.pageSize,
prefix: lastDir.ParenDir ? '/' + lastDir.ParenDir.replace(/^\//, '') : '',
},
success: function (res) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
if (res.result_code == 0) {
var result = res.data.sort((a, b) => {
var a1 = a.IsDir ? 1 : 0;
var b1 = b.IsDir ? 1 : 0;
return b1 - a1;
});
var fileList = [];
for (let i = 0, iLen = result.length; i < iLen; i++) {
const file = result[i];
if (self.currentFileList.findIndex(itm => `${itm.ParenDir}${itm.FileName}` == `${file.ParenDir}${file.FileName}`) >= 0) {
continue;
}
fileList.push(file);
}
self.data.dirMarkerChildrenMap[path + '-' + lastDir.marker] = result;
self.currentFileList = self.currentFileList.concat(fileList);
lastDir.marker = res.marker;
self.renderFileListAdd(fileList, result.length);
} else {
console.log(res);
}
});
}


},
error: function (err) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
console.log(err);
}
});
}

function getTextContent(uuid,filename){
$.ajax({
type:"GET",
url:ip + "/getgiteatext",
headers: {
authorization:token,
},
dataType:"text",
data:{
'uuid':uuid,
'filename':filename
},
async:false,
success:function(json){
textContent = json;
DatasetPreview.prototype.getPathChildren = function () {
this.renderFilePath();
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
var path = this.data.filePath.map((item) => item.path).join('/');
var cache = this.data.dirMarkerChildrenMap[path + '-' + lastDir.marker];
var self = this;
if (false && cache) {
self.currentFileList = cache;
this.renderFileList(cache);
} else {
$('#myCanvas_div .tabpannel.ui.form').addClass('loading');
$.ajax({
type: "get",
url: `/api/v1/attachments/get_dir`,
dataType: "json",
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
marker: '',
pageSize: this.pageSize,
prefix: lastDir.ParenDir ? '/' + lastDir.ParenDir.replace(/^\//, '') : '',
},
error:function(response) {
success: function (res) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
if (res.result_code == 0) {
var result = res.data.sort((a, b) => {
var a1 = a.IsDir ? 1 : 0;
var b1 = b.IsDir ? 1 : 0;
return b1 - a1;
});
self.data.dirMarkerChildrenMap[path + '-' + lastDir.marker] = result;
lastDir.marker = res.marker;
self.currentFileList = result;
self.currentFile = '';
self.renderFileList(result);
} else {
console.log(res);
}
},
error: function (err) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
console.log(err);
}
});
}



/*
function previewDataSetFile(uuid,filename){
console.log('uuid=' + uuid + " filename=" + filename);
loadimg(uuid,filename);
}

function loadimg(uuid,filename){
img.src = ip + "/getgiteaimage?uuid=" + uuid + "&filename=" + filename;
var fname = filename.substring(filename.lastIndexOf('/') + 1);
$("#filename").text(fname);
}
*/

function loadimg(){
var length = labeltastresult[fileindex].pic_image_field.length;
 if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".json" 
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".xml"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".txt"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".csv"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".md"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".py"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".sh"){
//文本
canvas.style.display="none";
document.getElementById("textcontent").style.display="block";
getTextContent(dataset_id,labeltastresult[fileindex].pic_image_field);
$('#textcontent').height(canvas.height-40)
$("#textcontent").text(textContent);
}else{
if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".jpeg" 
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".jpg"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".bmp"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".gif"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".png"){
canvas.style.display="block";
document.getElementById("textcontent").style.display="none";
img.src = ip + "/getgiteaimage?uuid=" + dataset_id + "&filename=" + labeltastresult[fileindex].pic_image_field;
}else{
canvas.style.display="none";
document.getElementById("textcontent").style.display="block";
$('#textcontent').height(canvas.height)
$("#textcontent").text("暂不支持预览");

}
}
var fname = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/') + 1);
$("#filename").text(fname);
}

img.onload = function(){

canvas.width = document.getElementById("win_canvas").offsetWidth;
canvas.height = document.getElementById("win_canvas").offsetHeight-40;
//调整画布大小
// if ((img.width/img.height)<(canvas.width/canvas.height)){
// canvas.width=canvas.height * img.width / img.height;
// }
// else{
// canvas.height=canvas.width * img.height / img.width;
// }
drawimage();
}

function isEmpty(str){
if(typeof str == "undefined" || str == null || str == ""){
return true;
}
return false;
}
function drawimage() {
parse_labelinfo(labeltastresult[fileindex].label_info);
// 清除画布,准备绘制
context.clearRect(0, 0, canvas.width, canvas.heigth);
// modal_context.cleararc
context.drawImage(img,0,0,img.width,img.height,0,0,canvas.width, canvas.height);
for(var i=0; i<rects.length; i++) {
var rect = rects[i];
rectxywh = new Array(4);
rectxywh_tmp = rect.getXYWH();
rectxywh[0] = rectxywh_tmp[0] / canvas.width * canvas.width;
rectxywh[1] = rectxywh_tmp[1] / canvas.height * canvas.height;
rectxywh[2] = rectxywh_tmp[2] / canvas.width * canvas.width;
rectxywh[3] = rectxywh_tmp[3] / canvas.height * canvas.height;
// 绘制矩形

context.lineWidth = 3;
if(rect.type == "person"){
context.strokeStyle = color_person[ i % 4];
}else{
context.strokeStyle=color_dict[rect.type];
}
context.strokeRect(rectxywh[0],rectxywh[1],rectxywh[2],rectxywh[3]);
context.font = "15px Georgia";
context.fillStyle= context.strokeStyle;

context.fillText(rect.type, rectxywh[0],rectxywh[1]-5);
for(var j=0; j<4; j++){
var p_tmp = rect.points[j];
var p = new point(0,0);
p.x = p_tmp.x/ canvas.width * canvas.width;;
p.y = p_tmp.y / canvas.height * canvas.height;
context.fillStyle = color_dict["point"];
context.fillRect(p.x-2,p.y-2,4,4);
}
}
for (var i=0; i<masks.length; i++){
context.strokeStyle="purple"
var mask =masks[i];
context.lineWidth = 2;
for (var j=1; j<mask.points.length; j++){
context.beginPath();
context.moveTo(mask.points[j-1].x, mask.points[j-1].y);
context.lineTo(mask.points[j].x,mask.points[j].y);
context.stroke();
// modal_context.closePath();
}
context.moveTo(mask.points[mask.points.length-1].x,mask.points[mask.points.length-1].y);
context.lineTo(mask.points[0].x,mask.points[0].y);
context.stroke();
context.closePath();
for (var j=0; j<mask.points.length; j++){
var p = mask.points[j]
context.fillStyle = color_dict["point"];
context.fillRect(p.x-2,p.y-2,4,4);
}
}
}
function parse_labelinfo(labelinfo){
rects.length = 0;
masks.length = 0;
pointShapes.length = 0;
if(!isEmpty(labelinfo)){
var label_arr = JSON.parse(labelinfo);
for(var i=0;i<label_arr.length;i++){
if(!isEmpty(label_arr[i].mask)){
cls=label_arr[i].class_name;
var tmpMask = new maskar(getCanvasLocationX(label_arr[i].mask[0]),getCanvasLocationY(label_arr[i].mask[1]),cls);
for(var j = 2; j < label_arr[i].mask.length; j+=2){
tmpMask.points.push(new point(getCanvasLocationX(label_arr[i].mask[j]),getCanvasLocationY(label_arr[i].mask[j+1])));
}
if(!isEmpty(label_arr[i].id)){
tmpMask.id= label_arr[i].id;
}
if(!isEmpty(label_arr[i].blurred)){
tmpMask.blurred = label_arr[i].blurred;
}
if(!isEmpty(label_arr[i].goodIllumination)){
tmpMask.goodIllumination = label_arr[i].goodIllumination;
}
if(!isEmpty(label_arr[i].frontview)){
tmpMask.frontview = label_arr[i].frontview;
}
tmpMask.finish = true;
masks.push(tmpMask);
}else if(!isEmpty(label_arr[i].box)){
x1 = getCanvasLocationX(label_arr[i].box[0]);
y1 = getCanvasLocationY(label_arr[i].box[1]);
x2 = getCanvasLocationX(label_arr[i].box[2]);
y2 = getCanvasLocationY(label_arr[i].box[3]);
cls=label_arr[i].class_name;
score = label_arr[i].score;
rect = new rectar(x1,y1,x2,y2,cls,score);
if(!isEmpty(label_arr[i].id)){
rect.id= label_arr[i].id;
}
if(!isEmpty(label_arr[i].blurred)){
rect.blurred = label_arr[i].blurred;
}
if(!isEmpty(label_arr[i].goodIllumination)){
rect.goodIllumination = label_arr[i].goodIllumination;
}
if(!isEmpty(label_arr[i].frontview)){
rect.frontview = label_arr[i].frontview;
}
rects.push(rect);
}else if(!isEmpty(label_arr[i].keypoints)){
cls=label_arr[i].class_name;
score = label_arr[i].score;
var pointShapeObj = new pointShape(getCanvasLocationX(label_arr[i].keypoints[0]),getCanvasLocationY(label_arr[i].keypoints[1]),cls,score);
pointShapes.push(pointShapeObj);
}
}
}
}

function point(x,y){
this.x = x;
this.y = y;
this.isSelected = false;
};

function pointShape(x,y,type,score=1.0){
this.x = x;
this.y = y;
this.isSelected = false;
this.type = type;
this.score = score;
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = false; //照明
this.frontview = false;//正面图
}

function rectar(x1,y1,x2,y2, type, score=1.0){
// this.x = x;
// this.y = y;
// this.width = width;
// this.height = height;
this.type = type;
this.score = score;
//0--1,
//| |
//2--3
this.points = [new point(x1,y1), new point(x1, y2),new point(x2, y1),new point(x2, y2)];
this.getXYWH = function(){
var x_min=Math.min(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var x_max=Math.max(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var y_min=Math.min(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
var y_max=Math.max(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
return [x_min,y_min,x_max-x_min,y_max-y_min];
}
this.getX1Y1X2Y2 = function(){
var x_min=Math.min(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var x_max=Math.max(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var y_min=Math.min(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
var y_max=Math.max(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
return [x_min,y_min,x_max,y_max];
});
}
this.getdiapid = function(pid){//获取对角点
var twooverlapped,fouroverlapped;
for (var i=0;i<4;i++){
if ((this.points[pid].x!=this.points[i].x)&&(this.points[pid].y!=this.points[i].y)){
return i;
}
if ((this.points[pid].x!=this.points[i].x)||(this.points[pid].y!=this.points[i].y)){
twooverlapped=i;
}
if (i!=pid) fouroverlapped=i;
};

}
if (twooverlapped)
return twooverlapped;
return fouroverlapped;
DatasetPreview.prototype.renderFileListAdd = function (files, length) {
var domC = $('#filelist');
domC.find('.file-more').remove();
for (let i = 0, iLen = files.length; i < iLen; i++) {
const file = files[i];
const fileEl = $(`<div class="file-item" title="${file.FileName}">
<i width="16" height="16" aria-hidden="true" style="color: ${file.IsDir ? 'rgb(91, 185, 115);' : ''}" class="icon ${file.IsDir ? 'folder outline' : 'file alternate outline'}"></i>
<span>${file.FileName}</span>
</div>`);
fileEl.data('data', file);
domC.append(fileEl);
}
this.mouseonpoint = false;
this.mouseonrect = false;
this.isSelected = false;
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = true; //照明
this.frontview = true;//正面图
};



function maskar(x0,y0,type){
this.type = type;
this.points = [new point(x0,y0)];
this.finish = false;
this.mouseonpoint = false;
this.mouseonmask = false;
this.isSelected = false;
this.getX1Y1 = function(){return [this.points[0].x,this.points[0].y]}
this.getBound = function(){
mlen = this.points.length;
var minX = 999999999, minY = 999999999, maxX = -1, maxY = -1;
for (var i = 0; i < mlen; i ++){
if(minX > this.points[i].x){
minX = this.points[i].x;
}
if(maxX < this.points[i].x){
maxX = this.points[i].x;
}
if(minY > this.points[i].y){
minY = this.points[i].y;
}
if(maxY < this.points[i].y){
maxY = this.points[i].y;
}
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
if (length >= this.pageSize && lastDir.marker) {
domC.append(`<div class="file-more">${$('#lang-seemore').text()}</div>`);
}
return [minX, minY, maxX, maxY];
}
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = true; //照明
this.frontview = true;//正面图
}

function getCanvasLocationX(num){
return Math.round(num * canvas.width/parseInt(img.width));
}

function getCanvasLocationY(num){
return Math.round(num * canvas.height/parseInt(img.height));
}


function page(current,pageSize){
list(current,pageSize);
showfilelist();
breadFiles();
loadimg();
setPage(tablePageData,pageSize);
}


getLabelInfo(dataset_id);
showlabelflist();


function nextPage(){
var current = $('#displayPage1').text();
page(current,pageSize);
}

function prePage(){
var current =$('#displayPage1').text();
if(current > 1){
page(current - 2,pageSize);
}
}

function goPage(){
var goNum = $('#goNum').val();
};

var pageTotal = $("#totalNum").text();
var pageNum = parseInt(pageTotal/pageSize);
if(pageTotal%pageSize!=0){
pageNum += 1;
}else {
pageNum = pageNum;
}
if (goNum<=0){
alert("请输入大于0的数值");
DatasetPreview.prototype.renderFileList = function (files) {
var domC = $('#filelist').empty();
var findFile = false;
for (let i = 0, iLen = files.length; i < iLen; i++) {
const file = files[i];
const fileEl = $(`<div class="file-item" title="${file.FileName}">
<i width="16" height="16" aria-hidden="true" style="color: ${file.IsDir ? 'rgb(91, 185, 115);' : ''}" class="icon ${file.IsDir ? 'folder outline' : 'file alternate outline'}"></i>
<span>${file.FileName}</span>
</div>`);
fileEl.data('data', file);
domC.append(fileEl);
}
else if(goNum<=pageNum){
page(goNum - 1,pageSize);
if (!findFile) {
this.currentFile = null;
this.renderPleseSelectFile();
}
else{
alert("不能超出总页码!");
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
if (files.length >= this.pageSize && lastDir.marker) {
domC.append(`<div class="file-more">${$('#lang-seemore').text()}</div>`);
}
}
};

$("#goNum").keydown(function (e) {
if (e.keyCode == 13) {
goPage();
DatasetPreview.prototype.renderPreview = function (file) {
var fileName = file.FileName;
if (this.supportImgReg.test(fileName)) {
console.log('renderImage');
$('#textcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').hide();
$('#imgcontent').attr('src', `/api/v1/attachments/get_image_content?uuid=${this.datasetData.uuid}&filePath=${file.ParenDir + file.FileName}&type=${this.datasetData.type}&_csrf=${this.datasetData.csrf}`).show();
} else if (this.supportTxtReg.test(fileName)) {
console.log('getFileText');
this.getFileText(file);
} else {
console.log('not support');
this.renderNotSupport();
}
});

function setPage(pageData,pageSize){
if (isEmpty(pageData)){
return;
}
var startIndex = pageData.current * pageSize;
if(pageData.total > 0){
startIndex = startIndex + 1;
}
if(startIndex < 10){
$('#startIndex').text(" " + (startIndex));
}else{
$('#startIndex').text(startIndex);
}
var endIndex = pageData.current * pageSize + pageData.data.length;
if(endIndex < 10){
$('#endIndex').text(" " + (endIndex));
}else{
$('#endIndex').text(endIndex);
}
$('#totalNum').text(pageData.total);
$('#displayPage1').text(pageData.current + 1);


if(pageData.current == 0){
$('#prePage').removeAttr("href");
$('#prePage').attr('style','color:#f5f5f6;');
}
else{
$('#prePage').attr("href","javascript:prePage()");
$('#prePage').attr('style','color:#000;');
}

if((pageData.current + 1) * pageSize >= pageData.total){
$('#nextPage').removeAttr("href");
$('#nextPage').attr('style','color:#f5f5f6;')
}
else{
$('#nextPage').attr("href","javascript:nextPage()");
$('#nextPage').attr('style','color:#000;');
}
};

var pageTotal = pageData.total;
var pageNum = parseInt(pageTotal/pageSize);
if(pageTotal%pageSize!=0){
pageNum += 1;
}else {
pageNum = pageNum;
DatasetPreview.prototype.renderNotSupport = function () {
$('#imgcontent').hide();
$('#textcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').show();
}
$("#totalPageNum").text(pageNum);
}

function clickfilelist(index){
fileindex=index;
loadimg();
//drawimage();
breadFiles()
showfilelist();
}

function clickNext(){
if(fileindex<tableData.length-1) {
next();
}else{
if((tablePageData.current + 1) * pageSize >= tablePageData.total){
return;
}
nextPage();
DatasetPreview.prototype.renderPleseSelectFile = function () {
$('#imgcontent').hide();
$('#textcontent').hide();
$('#win_canvas .not-support').hide();
$('#win_canvas .select-file').show();
}
}


function next(){
if(fileindex<tableData.length-1) {fileindex=fileindex+1;}
loadimg();
//drawimage();
breadFiles()
showfilelist();
}

function clickLast(){
if(fileindex == 0){
lastindex=true;
prePage();
lastindex=false;

}else{
last();
}
}

function last(){

if(fileindex>0) {fileindex=fileindex-1;}
loadimg();
//drawimage();
breadFiles();
showfilelist();
}


// function showfilelist(){
// var htmlstr="";
// for (var i=0;i<labeltastresult.length;i++){
// var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1);
// var lablebg=" style=\"cursor:pointer\"";
// if (i==fileindex){lablebg=" style=\"background:#eee;color:#5a5a5a;cursor:pointer;\"";}
// htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+ lablebg+"><td>"+ fname+ "</td></tr>";
// };
// document.getElementById("filelist").innerHTML=htmlstr;
// }

DatasetPreview.prototype.renderText = function (content) {
$('#imgcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').hide();
$('#textcontent').empty().text(content).show();
};

function showfilelist(){
// var filename_title = $('a.section:first').text()
// filename_title = filename_title.substring(0,filename_title.lastIndexOf('.'))
var filename_index = labeltastresult[0].pic_image_field.indexOf("/",70);
filename_title = labeltastresult[0].pic_image_field.substring(filename_index + 1);
filename_title = filename_title.substring(0,filename_title.indexOf('/'))
var htmlstr = '';
// htmlstr += '<div class="ui list">';
htmlstr += '<div class="item" style="padding:1.2em;border-bottom:0;display: table;width: 100%;">'
htmlstr += '<i class="caret down icon"></i>'
htmlstr += '<div class="content" style="background:#fff">'
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 600;">'+filename_title+'</div>'
htmlstr += '<div class="list" style="padding:1.2em">'
for (var i=0;i<labeltastresult.length;i++){
var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1);
//console.log(labeltastresult[i])
if(labeltastresult[i].pic_image_field.length > 70){
var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70);
//console.log(tmpIndex)
if(tmpIndex != -1){
fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1);
fname = fname.substring(fname.indexOf('/')+1);
DatasetPreview.prototype.getFileText = function (file) {
var cache = this.data.fileContentMap[file.ParenDir + file.FileName];
var self = this;
if (false && cache) {
self.renderText(cache);
} else {
$.ajax({
type: "get",
url: "/api/v1/attachments/get_txt_content",
headers: { authorization: this.datasetData.csrf, },
dataType: "json",
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
type: this.datasetData.type,
filePath: file.ParenDir + file.FileName,
},
success: function (res) {
self.data.fileContentMap[file.ParenDir + file.FileName] = res.data;
const data = res.data || [];
if (res.result_code == 0) {
self.renderText(data.join(''));
} else if (res.result_code == -1) {
self.renderText(res.msg);
} else {
self.renderNotSupport();
}
},
error: function (err) {
console.log(err);
self.renderNotSupport();
}
});
}
htmlstr += '<div class="item" onclick=\"clickfilelist('+i+');\" style="border-bottom:0;padding-bottom:0.9em;cursor:pointer">'
htmlstr += '<div class="content" style="background:#fff;padding:0;">'
if(i==fileindex){
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 100;color:#0366d6;overflow: hidden;text-overflow:ellipsis;">'+fname+'</div>'
}
else{
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 100;overflow: hidden;text-overflow:ellipsis;">'+fname+'</div>'
}
htmlstr += '</div>'
htmlstr += '</div>'
};
htmlstr += '</div>'
htmlstr += '</div>'
htmlstr += '</div>'
document.getElementById("filelist").innerHTML=htmlstr;
}


function breadFiles(){

// for (var i=0;i<labeltastresult.length;i++){
// var fname_full_path=""
// if(labeltastresult[i].pic_image_field.length > 70){
// var tmp_index = labeltastresult[i].pic_image_field.indexOf("/",70);
// if(tmp_index != -1){
// fname_full_path = labeltastresult[i].pic_image_field.substring(tmp_index + 1);
// }
// var fname_path = fname_full_path.split('/')
// html_breadFile += '<div class="section">'+fname_full_path+'.zip'+'</div>'
// for(var i=1;i<fname_path.length;i++){
// html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
// html_breadFile += '<div class="section">'+fname_path[i]+'</div>'

// }
// }
// else{


// }
// }
var fname_full_path=""
var filename_title = $('a.section:first').text()
filename_title = filename_title.substring(0,filename_title.lastIndexOf('.'))
var tmp_index = tableData[fileindex].pic_image_field.indexOf("/",70);
if(tmp_index != -1){
fname_full_path = tableData[fileindex].pic_image_field.substring(tmp_index + 1);
}
var fname_path = fname_full_path.split('/')
//console.log(fname_path)
// var filename_text = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/')+1)
var html_breadFile = ''
// var source_name = filename_title+'.zip'
// html_breadFile += '<div class="section">'+source_name+'</div>'
// html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
html_breadFile += '<div class="section">'+filename_title+'</div>'
html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
for (var i=0;i<fname_path.length;i++){
html_breadFile += '<div class="section">'+fname_path[i]+'</div>'
html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
DatasetPreview.prototype.offsetPrview = function (offset) {
var fileList = this.currentFileList.filter(function (item) { return !item.IsDir });
if (!fileList.length) {
this.renderPleseSelectFile();
return;
}
document.getElementById("breadFile").innerHTML=html_breadFile

}

function showlabelflist(){
if(!isEmpty(labelInfo)){
var resLabelInfo = JSON.parse(labelInfo)
var textInfo = resLabelInfo["type"]
var html_labelFile = ''
for (var i=0;i<textInfo.length;i++){

html_labelFile += `<span style="display:block;width:70%;margin:0.6em 15%;padding-left:1.5em;padding-top:0.4em;padding-bottom:0.4em;font-size:12px;" class="labelInfo">${textInfo[i]}</span>`

var file = this.currentFile;
var index = -1;
var nextIndex = 0;
if (file) {
index = fileList.findIndex(function (item) { return (item.ParenDir + item.FileName) == (file.ParenDir + file.FileName); });
index = Math.max(0, index);
nextIndex = (offset + index + fileList.length) % fileList.length;
}
document.getElementById("labellist").innerHTML=html_labelFile
setColor()
}
else{
return
}

}
function setColor(){
colorinfo1 = ['rgba(0, 199, 255, 0.4)','rgba(114, 46, 209, 0.4)','rgba(188, 100, 164, 0.4)','rgba(153, 204, 0, 0.4)','rgba(51, 204, 153, 0.4)','rgba(255, 204, 51, 0.4)',
'rgba(71, 255, 71, 0.4)','rgba(255, 154, 71, 0.4)','rgba(71, 126, 255, 0.4)','rgba(71, 255, 255, 0.4)','rgba(255, 247, 71, 0.4)','rgba(196, 127, 255, 0.4)','rgba(233, 84, 100, 0.4)',
'rgba(255, 71, 204, 0.4)',' rgba(43, 199, 160, 0.4)']
colorinfo2 = ['#00C7FF','#722ED1','#BC64A4','#99CC00','#33CC99','#FFCC33','#47FF47','#FF9A47','#477EFF','#47FFFF','#FFF747','#C47FFF','#E95464','#FF47CC','#2BC7A0']
var el_span = document.querySelectorAll("span.labelInfo")
for (var i=0;i<el_span.length;i++){
// var colorinfo = ~~(Math.random()*(1<<24))
// var colorinfo1 = '#'+(colorinfo).toString(16)
// var colorinfo2 = '#'+(colorinfo+100).toString(16)
el_span[i].style.backgroundColor = colorinfo1[i]
el_span[i].style.borderLeft = '5px solid'+ colorinfo2[i]
}
this.currentFile = fileList[nextIndex];
var self = this;
$('#filelist .file-item').removeClass('active');
$('#filelist .file-item').map((_, item) => {
var eleObj = $(item);
var data = eleObj.data('data');
if ((data.ParenDir + data.FileName) == (self.currentFile.ParenDir + self.currentFile.FileName)) {
eleObj.addClass('active');
self.renderPreview(data);
}
})
};

}
function getLabelInfo(uuid){
$.ajax({
type:"GET",
url:ip + "/getlabelinfo",
headers: {
authorization:token,
},
dataType:"text",
data:{
'uuid':uuid
},
async:false,
success:function(json){
labelInfo = json;
},
error:function(response) {
DatasetPreview.prototype.eventInit = function () {
var self = this;
$('#filelist').on('click', '.file-item', function () {
var eleObj = $(this);
var file = eleObj.data('data');
if (file.IsDir) {
self.nextDirs(file);
} else {
$('#filelist .file-item').removeClass('active');
eleObj.addClass('active');
self.currentFile = file;
self.renderPreview(file);
}
});
}).on('click', '.file-more', function () {
self.getPathChildrenMore();
});
$('#file_path_container').on('click', '.section', function () {
var eleObj = $(this).parent();
var pathData = eleObj.data('data');
var index = self.data.filePath.findIndex(function (item) { return item.path == pathData.path });
var newPath = self.data.filePath.slice(0, index + 1);
self.data.filePath = newPath;
self.getPathChildren();
});
$('#myCanvas_div').on('click', '.prev_view_btn', function () {
self.offsetPrview(-1);
}).on('click', '.next_view_btn', function () {
self.offsetPrview(1);
});
};

}
$(document).ready(function () {
window.DatasetPreviewController = new DatasetPreview();
})
})();

+ 7
- 3
routers/api/v1/api.go View File

@@ -59,10 +59,11 @@
package v1

import (
"code.gitea.io/gitea/routers/reward/point"
"net/http"
"strings"

"code.gitea.io/gitea/routers/reward/point"

"code.gitea.io/gitea/services/memory"

"code.gitea.io/gitea/routers/response"
@@ -758,14 +759,17 @@ func RegisterRoutes(m *macaron.Macaron) {
}, reqToken())

m.Group("/attachments", func() {

m.Get("/:uuid", repo.GetAttachment)
m.Get("/get_chunks", repo.GetSuccessChunks)
m.Get("/new_multipart", repo.NewMultipart)
m.Get("/get_multipart_url", repo.GetMultipartUploadUrl)
m.Post("/complete_multipart", repo.CompleteMultipart)

}, reqToken())
m.Group("/attachments", func() {
m.Get("/get_dir", repo.GetAttachmentDir)
m.Get("/get_image_content", repo.GetAttachmentImageContent)
m.Get("/get_txt_content", repo.GetAttachmentTxtContent)
})
m.Group("/attachments/model", func() {
m.Get("/get_chunks", repo.GetModelChunks)
m.Get("/new_multipart", repo.NewModelMultipart)


+ 12
- 0
routers/api/v1/repo/attachments.go View File

@@ -54,6 +54,18 @@ func checkDatasetPermission(ctx *context.APIContext) string {
return ""
}

func GetAttachmentDir(ctx *context.APIContext) {
routeRepo.GetDirSomeFiles(ctx.Context)
}

func GetAttachmentImageContent(ctx *context.APIContext) {
routeRepo.GetImageContent(ctx.Context)
}

func GetAttachmentTxtContent(ctx *context.APIContext) {
routeRepo.GetTxtContent(ctx.Context)
}

func NewMultipart(ctx *context.APIContext) {
if errStr := checkDatasetPermission(ctx); errStr != "" {
ctx.JSON(200, map[string]string{


+ 33
- 13
routers/org/teams.go View File

@@ -6,6 +6,7 @@
package org

import (
"fmt"
"net/http"
"path"
"strings"
@@ -310,18 +311,37 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
}
t.Description = form.Description
if t.Authorize < models.AccessModeOwner {
var units = make([]models.TeamUnit, 0, len(form.Units))
for _, tp := range form.Units {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
log.Info("t.Authorize < models.AccessModeOwner")
if t.Authorize < models.AccessModeAdmin {
var units = make([]models.TeamUnit, 0, len(form.Units))
for _, tp := range form.Units {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
}
} else {
log.Info("t.Authorize = models.AccessModeAdmin")

var units = make([]models.TeamUnit, 0, len(models.AllRepoUnitTypes))
for _, tp := range models.AllRepoUnitTypes {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
}
}
}
t.CanCreateOrgRepo = form.CanCreateOrgRepo
@@ -335,7 +355,7 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
return
}
log.Info("isAuthChanged=" + fmt.Sprint(isAuthChanged) + " isIncludeAllChanged=" + fmt.Sprint(isIncludeAllChanged))
if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil {
ctx.Data["Err_TeamName"] = true
switch {


+ 368
- 0
routers/repo/attachment_dir.go View File

@@ -0,0 +1,368 @@
package repo

import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"path"
"strings"
"time"

"golang.org/x/text/encoding/simplifiedchinese"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/redis/redis_client"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
)

type DirRedisCache struct {
DirList []storage.FileInfo
Marker string
}

func GetDirSomeFiles(ctx *context.Context) {
uuid := ctx.Query("uuid")
marker := ctx.Query("marker")
pageSize := ctx.QueryInt("pageSize")
prefix := ctx.Query("prefix")
cacheKey := uuid + prefix + marker + " " + fmt.Sprint(pageSize)
//delimiter := ctx.Query("delimiter")
attach, err := models.GetAttachmentByUUID(uuid)
if err == nil {
cacheResult, err := getAttachmentDirFromCache(cacheKey)
if err == nil {
log.Info("load from cache.")
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": cacheResult.DirList,
"marker": cacheResult.Marker,
})
return
}
if attach.Type == models.TypeCloudBrainOne {
re, marker, err := storage.GetDirsSomeFileMinio(setting.Attachment.Minio.Bucket,
setting.Attachment.Minio.BasePath+
models.AttachmentRelativePath(attach.UUID)+
attach.UUID, prefix, marker, pageSize)
if err == nil {
setAttachmentDirToCache(cacheKey, DirRedisCache{
DirList: re,
Marker: marker,
})
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": re,
"marker": marker,
})
return
}
} else if attach.Type == models.TypeCloudBrainTwo {
re, marker, err := storage.GetDirsSomeFile(setting.Bucket,
setting.BasePath+
models.AttachmentRelativePath(attach.UUID)+
attach.UUID, prefix, marker, pageSize)
if err == nil {
setAttachmentDirToCache(cacheKey, DirRedisCache{
DirList: re,
Marker: marker,
})
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": re,
"marker": marker,
})
return
}
}
}
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"data": "",
})
}

func GetImageContent(ctx *context.Context) {
uuid := ctx.Query("uuid")
fileName := ctx.Query("filePath")
storageType := ctx.QueryInt("type")
if storageType == 0 {
getMinioImageContent(uuid, fileName, ctx)
} else {
if storageType == 1 {
getObsImageContent(uuid, fileName, ctx)
}
}
}

func GetTxtContent(ctx *context.Context) {
uuid := ctx.Query("uuid")
fileName := ctx.Query("filePath")
storageType := ctx.QueryInt("type")
if storageType == 0 {
getMinioTxtContent(uuid, fileName, ctx)
} else {
if storageType == 1 {
getObsTxtContent(uuid, fileName, ctx)
}
}
}

func getObsImageContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("obs objectName=" + objectName)
body, err := storage.ObsDownloadAFile(setting.Bucket, objectName)
if err != nil {
log.Info("upload error.")
} else {
defer body.Close()
ctx.Resp.Header().Set("Content-Type", "image/jpg;charset=utf-8")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}

func getObsTxtContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("obs objectName=" + objectName)
body, err := storage.ObsDownloadAFile(setting.Bucket, objectName)
if err != nil {
log.Info("download error.")
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": "Read file error.",
"data": "",
})
return
} else {
readS3Body(body, ctx)
}
}

func readS3Body(body io.ReadCloser, ctx *context.Context) {
defer body.Close()
result := make([]string, 0)
r := bufio.NewReader(body)
size := 0
for {
line, err := r.ReadString('\n')
if err == io.EOF {
result = append(result, toUTF8(line))
size += len(line)
if !toDealLine(result, line, size, ctx) {
return
}
break
}
if err != nil {
log.Info("read error,err=" + err.Error())
break
}
result = append(result, toUTF8(line))
size += len(line)
if !toDealLine(result, line, size, ctx) {
return
}
}
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"msg": "",
"data": result,
})
}

func toDealLine(result []string, line string, size int, ctx *context.Context) bool {
log.Info("line count=" + fmt.Sprint(len(result)) + " size=" + fmt.Sprint(size))
if len(result) > 2000 || size > 2*1024*1024 {
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": ctx.Tr("repo.attachmentfilesizetobig"),
"data": "",
})
return false
}
return true
}

func toUTF8(line string) string {
lineBytes := []byte(line)
if isUtf8(lineBytes) {
return line
}
if isGBK(lineBytes) {
log.Info("this is gbk")
gbkBytes, err := simplifiedchinese.GBK.NewDecoder().Bytes(lineBytes) //gbk 转 utf-8
if err == nil {
return string(gbkBytes)
}
}
return line
}

func toGBK(line string) string {
lineBytes := []byte(line)
if !isGBK(lineBytes) {
gbkBytes, err := simplifiedchinese.GBK.NewEncoder().Bytes(lineBytes) //utf-8 转 gbk
if err == nil {
return string(gbkBytes)
}
}
return line
}

func isGBK(data []byte) bool {
length := len(data)
var i int = 0
for i < length {
//fmt.Printf("for %x\n", data[i])
if data[i] <= 0xff {
//编码小于等于127,只有一个字节的编码,兼容ASCII吗
i++
continue
} else {
//大于127的使用双字节编码
if data[i] >= 0x81 &&
data[i] <= 0xfe &&
data[i+1] >= 0x40 &&
data[i+1] <= 0xfe &&
data[i+1] != 0xf7 {
i += 2
continue
} else {
return false
}
}
}
return true
}

func getMinioImageContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("minio objectName=" + objectName)
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, objectName)
if err != nil {
log.Info("download error.")
} else {
defer body.Close()
ctx.Resp.Header().Set("Content-Type", "image/jpg;charset=utf-8")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}

func getMinioTxtContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("minio objectName=" + objectName)
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, objectName)
if err != nil {
log.Info("download error.")
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": "Read file error.",
"data": "",
})
return
} else {
readS3Body(body, ctx)
}
}

func preNUm(data byte) int {
str := fmt.Sprintf("%b", data)
var i int = 0
for i < len(str) {
if str[i] != '1' {
break
}
i++
}
return i
}

func isUtf8(data []byte) bool {
for i := 0; i < len(data); {
if data[i]&0x80 == 0x00 {
// 0XXX_XXXX
i++
continue
} else if num := preNUm(data[i]); num > 2 {
// 110X_XXXX 10XX_XXXX
// 1110_XXXX 10XX_XXXX 10XX_XXXX
// 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数
i++
for j := 0; j < num-1; j++ {
//判断后面的 num - 1 个字节是不是都是10开头
if data[i]&0xc0 != 0x80 {
return false
}
i++
}
} else {
//其他情况说明不是utf-8
return false
}
}
return true
}

func setAttachmentDirToCache(msgKey string, dirList DirRedisCache) {
msgMapJson, _ := json.Marshal(dirList)
redisValue := string(msgMapJson)
log.Info("set redis key=" + msgKey + " value=" + redisValue)
re, err := redis_client.Setex(msgKey, redisValue, 7*24*3600*time.Second)
if err == nil {
log.Info("re =" + fmt.Sprint(re))
} else {
log.Info("set redis error:" + err.Error())
}
}

func getAttachmentDirFromCache(msgKey string) (*DirRedisCache, error) {
valueStr, err := redis_client.Get(msgKey)
//msgMap := make(map[string]string, 0)
fileInfos := &DirRedisCache{}
if err == nil {
if valueStr != "" {
err1 := json.Unmarshal([]byte(valueStr), fileInfos)
if err1 != nil {
log.Info("unmarshal json failed. " + err1.Error())
return nil, err1
}
} else {
return nil, errors.New("cache is empty.")
}
} else {
log.Info("Failed to load from reids. " + err.Error())
return nil, err
}
return fileInfos, nil
}

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

@@ -127,6 +127,7 @@ func DirIndex(ctx *context.Context) {
ctx.Data["Path"] = dirArray
ctx.Data["Dirs"] = true
ctx.Data["Uuid"] = uuid
ctx.Data["Type"] = attachment.Type
ctx.Data["PageIsDataset"] = true

ctx.HTML(200, tplDirIndex)


+ 83
- 207
templates/repo/datasets/dirs/dir_preview.tmpl
File diff suppressed because it is too large
View File


+ 18
- 12
templates/repo/datasets/dirs/index.tmpl View File

@@ -1,22 +1,33 @@
<style>
form {margin-block-end: 0;}
form {margin-block-end: 0;}
#file_path_container .section {
color: rgb(50, 145, 248);
}
</style>
<div style="background:#fff">
{{template "base/head" .}}
<div class="repository dataset dir-list view">
{{template "repo/header" .}}
<script>
var DATASET_DATA = {
csrf: {{.CsrfToken}},
repoLink: {{$.RepoLink}},
link: {{$.Link}},
uuid: {{$.Uuid}},
type: {{.Type}},
path: {{.Path}},
isDir: {{.Dirs}},
};
</script>
<div>
<form class="ui container">
<div class="ui stackable grid {{if .Error}}hide{{end}}" id="dir-content">
<div class="row">
<div class="row" style="padding: 6px 0;">
<div class="column sixteen wide">
<div class="ui breadcrumb">
{{ range $index, $item := .Path }}<a class="section" href='{{$.Link}}/?parentDir={{if gt $index 0}}{{DatasetPathJoin $.Path $index "/"}}{{else}}{{end}}'>{{ $item }}</a><div class="divider"> / </div>{{ end }}
</div>
<div id="file_path_container" style="display:flex;flex-wrap:wrap;min-height:20px" class="ui breadcrumb "></div>
</div>
</div>
</div>
<div class="ui grid">
<div class="row" style="padding-top: 0.5rem;padding-bottom: 0;">
<div class="ui sixteen wide column">
@@ -27,12 +38,7 @@ form {margin-block-end: 0;}
</div>
</div>
</form>
</div>
</div>
</div>
</div>




{{template "base/footer" .}}

Loading…
Cancel
Save