Skip to content

Commit 9471d41

Browse files
committed
[feature] - files distribution system
1 parent 4a31b30 commit 9471d41

File tree

3 files changed

+318
-46
lines changed

3 files changed

+318
-46
lines changed

db-connector.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10070,6 +10070,24 @@ func GetAllFiles(ctx context.Context, orgId, namespace string) ([]File, error) {
1007010070
}
1007110071
}
1007210072

10073+
// Should check if it's a child org and get parent orgs files if that is distributed
10074+
foundOrg, err := GetOrg(ctx, orgId)
10075+
if err == nil && len(foundOrg.ChildOrgs) == 0 && len(foundOrg.CreatorOrg) > 0 && foundOrg.CreatorOrg != orgId {
10076+
parentOrg, err := GetOrg(ctx, foundOrg.CreatorOrg)
10077+
if err == nil {
10078+
parentFiles, err := GetAllFiles(ctx, parentOrg.Id, namespace)
10079+
if err == nil {
10080+
for _, f := range parentFiles {
10081+
if !f.SuborgDistributed {
10082+
continue
10083+
}
10084+
10085+
files = append(files, f)
10086+
}
10087+
}
10088+
}
10089+
}
10090+
1007310091
if project.CacheDb {
1007410092
data, err := json.Marshal(files)
1007510093
if err != nil {

files.go

Lines changed: 258 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,49 @@ func HandleGetFileNamespace(resp http.ResponseWriter, request *http.Request) {
571571
// FIXME: This double control is silly
572572
fileResponse.Files = append(fileResponse.Files, file)
573573
fileResponse.List = append(fileResponse.List, BaseFile{
574-
Name: file.Filename,
575-
ID: file.Id,
576-
Type: file.Type,
577-
UpdatedAt: file.UpdatedAt,
578-
Md5Sum: file.Md5sum,
579-
Status: file.Status,
580-
FileSize: file.FileSize,
574+
Name: file.Filename,
575+
ID: file.Id,
576+
Type: file.Type,
577+
UpdatedAt: file.UpdatedAt,
578+
Md5Sum: file.Md5sum,
579+
Status: file.Status,
580+
FileSize: file.FileSize,
581+
OrgId: file.OrgId,
582+
SuborgDistributed: file.SuborgDistributed,
581583
})
582584
}
583585
}
584586

587+
// If current org is sub org and file suborg distributed is true than add file to list
588+
foundOrg, err := GetOrg(ctx, user.ActiveOrg.Id)
589+
if err == nil && len(foundOrg.ChildOrgs) == 0 && len(foundOrg.CreatorOrg) > 0 {
590+
parentOrg, err := GetOrg(ctx, foundOrg.CreatorOrg)
591+
if err == nil {
592+
parentFiles, err := GetAllFiles(ctx, parentOrg.Id, namespace)
593+
if err == nil {
594+
for _, file := range parentFiles {
595+
if !file.SuborgDistributed {
596+
continue
597+
}
598+
if file.Namespace == namespace {
599+
fileResponse.Files = append(fileResponse.Files, file)
600+
fileResponse.List = append(fileResponse.List, BaseFile{
601+
Name: file.Filename,
602+
ID: file.Id,
603+
Type: file.Type,
604+
UpdatedAt: file.UpdatedAt,
605+
Md5Sum: file.Md5sum,
606+
Status: file.Status,
607+
FileSize: file.FileSize,
608+
OrgId: file.OrgId,
609+
SuborgDistributed: file.SuborgDistributed,
610+
})
611+
}
612+
}
613+
}
614+
}
615+
}
616+
585617
//log.Printf("[DEBUG] Found %d (%d:%d) files in org %s (%s) for namespace '%s'", len(files), len(fileResponse.Files), len(fileResponse.List), user.ActiveOrg.Name, user.ActiveOrg.Id, namespace)
586618

587619
// Standards to load directly from Github if applicable
@@ -1971,3 +2003,222 @@ func HandleDownloadRemoteFiles(resp http.ResponseWriter, request *http.Request)
19712003
resp.WriteHeader(200)
19722004
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
19732005
}
2006+
2007+
func HandleShareNamespace(resp http.ResponseWriter, request *http.Request) {
2008+
2009+
cors := HandleCors(resp, request)
2010+
if cors {
2011+
return
2012+
}
2013+
2014+
user, err := HandleApiAuthentication(resp, request)
2015+
if err != nil {
2016+
log.Printf("[AUDIT] Api authentication failed in share namespace: %s", err)
2017+
resp.WriteHeader(401)
2018+
resp.Write([]byte(`{"success": false}`))
2019+
return
2020+
}
2021+
2022+
if user.Role != "admin" {
2023+
log.Printf("User (%s) isn't admin during namespace share", user.Username)
2024+
resp.WriteHeader(401)
2025+
resp.Write([]byte(`{"success": false, "reason": "only admin can share namespace"}`))
2026+
return
2027+
}
2028+
2029+
var namespace string
2030+
location := strings.Split(request.URL.String(), "/")
2031+
if location[1] == "api" {
2032+
if len(location) <= 4 {
2033+
log.Printf("Path too short: %d", len(location))
2034+
resp.WriteHeader(401)
2035+
resp.Write([]byte(`{"success": false}`))
2036+
return
2037+
}
2038+
2039+
namespace = location[5]
2040+
}
2041+
2042+
body, err := ioutil.ReadAll(request.Body)
2043+
if err != nil {
2044+
log.Printf("Error with body read: %s", err)
2045+
resp.WriteHeader(401)
2046+
resp.Write([]byte(`{"success": false}`))
2047+
return
2048+
}
2049+
2050+
type shareNamespace struct {
2051+
SelectedFiles []string `json:"selectedFiles"`
2052+
}
2053+
2054+
var share shareNamespace
2055+
err = json.Unmarshal(body, &share)
2056+
if err != nil {
2057+
log.Printf("Failed unmarshaling (appauth): %s", err)
2058+
resp.WriteHeader(401)
2059+
resp.Write([]byte(`{"success": false}`))
2060+
return
2061+
}
2062+
2063+
if len(namespace) == 0 {
2064+
log.Printf("[ERROR] Missing namespace in share namespace")
2065+
resp.WriteHeader(401)
2066+
resp.Write([]byte(`{"success": false, "reason": "Missing namespace"}`))
2067+
return
2068+
}
2069+
2070+
if len(share.SelectedFiles) == 0 {
2071+
log.Printf("[ERROR] Missing selectedFiles in share namespace")
2072+
resp.WriteHeader(401)
2073+
resp.Write([]byte(`{"success": false, "reason": "Missing selectedFiles"}`))
2074+
return
2075+
}
2076+
2077+
ctx := GetContext(request)
2078+
for _, fileId := range share.SelectedFiles {
2079+
file, err := GetFile(ctx, fileId)
2080+
if err != nil {
2081+
log.Printf("[INFO] File %s not found: %s", fileId, err)
2082+
resp.WriteHeader(400)
2083+
resp.Write([]byte(`{"success": false}`))
2084+
return
2085+
}
2086+
2087+
file.Namespace = namespace
2088+
err = SetFile(ctx, *file)
2089+
if err != nil {
2090+
log.Printf("[ERROR] Failed setting file back to active")
2091+
resp.WriteHeader(500)
2092+
resp.Write([]byte(`{"success": false, "reason": "Failed setting file to active"}`))
2093+
return
2094+
}
2095+
}
2096+
2097+
log.Printf("[INFO] Successfully shared namespace %s for %d files", namespace, len(share.SelectedFiles))
2098+
resp.WriteHeader(200)
2099+
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "Namespace shared successfully!"}`)))
2100+
}
2101+
2102+
// destribute files to all sub orgs of parent org
2103+
func HandleSetFileConfig(resp http.ResponseWriter, request *http.Request) {
2104+
2105+
cors := HandleCors(resp, request)
2106+
if cors {
2107+
return
2108+
}
2109+
2110+
user, err := HandleApiAuthentication(resp, request)
2111+
if err != nil {
2112+
log.Printf("[AUDIT] Api authentication failed in load files: %s", err)
2113+
resp.WriteHeader(401)
2114+
resp.Write([]byte(`{"success": false}`))
2115+
return
2116+
}
2117+
2118+
if user.Role != "admin" {
2119+
log.Printf("User (%s) isn't admin during file edit config", user.Username)
2120+
resp.WriteHeader(401)
2121+
resp.Write([]byte(`{"success": false, "reason": "only admin can edit file config"}`))
2122+
return
2123+
}
2124+
2125+
var fileId string
2126+
location := strings.Split(request.URL.String(), "/")
2127+
if location[1] == "api" {
2128+
if len(location) <= 4 {
2129+
log.Printf("Path too short: %d", len(location))
2130+
resp.WriteHeader(401)
2131+
resp.Write([]byte(`{"success": false}`))
2132+
return
2133+
}
2134+
2135+
fileId = location[4]
2136+
}
2137+
2138+
body, err := ioutil.ReadAll(request.Body)
2139+
if err != nil {
2140+
log.Printf("Error with body read: %s", err)
2141+
resp.WriteHeader(401)
2142+
resp.Write([]byte(`{"success": false}`))
2143+
return
2144+
}
2145+
2146+
type configFile struct {
2147+
Id string `json:"id"`
2148+
Action string `json:"action"`
2149+
}
2150+
2151+
var config configFile
2152+
err = json.Unmarshal(body, &config)
2153+
if err != nil {
2154+
log.Printf("Failed unmarshaling (appauth): %s", err)
2155+
resp.WriteHeader(401)
2156+
resp.Write([]byte(`{"success": false}`))
2157+
return
2158+
}
2159+
2160+
if config.Id != fileId {
2161+
resp.WriteHeader(401)
2162+
resp.Write([]byte(`{"success": false, "reason": "Bad ID match"}`))
2163+
return
2164+
}
2165+
2166+
ctx := GetContext(request)
2167+
file, err := GetFile(ctx, fileId)
2168+
if err != nil {
2169+
log.Printf("[INFO] File %s not found: %s", fileId, err)
2170+
resp.WriteHeader(400)
2171+
resp.Write([]byte(`{"success": false}`))
2172+
return
2173+
}
2174+
2175+
if config.Action == "suborg_distribute" {
2176+
org, err := GetOrg(ctx, user.ActiveOrg.Id)
2177+
if err != nil {
2178+
log.Printf("[ERROR] Failed getting org %s: %s", file.OrgId, err)
2179+
resp.WriteHeader(403)
2180+
resp.Write([]byte(`{"success": false, "reason": "Failed getting org"}`))
2181+
return
2182+
}
2183+
2184+
// Check if org doesn't have a creator org
2185+
if len(org.CreatorOrg) != 0 {
2186+
log.Printf("[INFO] Org %s has creator org %s, can't distribute", org.Id, org.CreatorOrg)
2187+
resp.WriteHeader(400)
2188+
resp.Write([]byte(`{"success": false, "reason": "Can't distribute auth for suborgs"}`))
2189+
return
2190+
}
2191+
2192+
if file.SuborgDistributed {
2193+
file.SuborgDistributed = false
2194+
2195+
} else {
2196+
file.SuborgDistributed = true
2197+
}
2198+
2199+
err = SetFile(ctx, *file)
2200+
if err != nil {
2201+
log.Printf("[ERROR] Failed setting file back to active")
2202+
resp.WriteHeader(500)
2203+
resp.Write([]byte(`{"success": false, "reason": "Failed setting file to active"}`))
2204+
return
2205+
}
2206+
2207+
}
2208+
2209+
//if current org is suborg and file is distributed, get the parent org file
2210+
foundOrg, err := GetOrg(ctx, user.ActiveOrg.Id)
2211+
if err == nil {
2212+
for _, childOrg := range foundOrg.ChildOrgs {
2213+
cacheKey := fmt.Sprintf("files_%s_%s", childOrg.Id, file.Namespace)
2214+
log.Printf("Clearing cache for %s", cacheKey)
2215+
DeleteCache(ctx, cacheKey)
2216+
}
2217+
}
2218+
2219+
log.Printf("[INFO] Successfully updated file: %s for org: %s", file.Id, user.ActiveOrg.Id)
2220+
2221+
resp.WriteHeader(200)
2222+
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "File updated successfully!"}`)))
2223+
2224+
}

structs.go

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,38 +1434,39 @@ type NotificationCached struct {
14341434
}
14351435

14361436
type File struct {
1437-
Id string `json:"id" datastore:"id"`
1438-
ReferenceFileId string `json:"reference_file_id" datastore:"reference_file_id"`
1439-
Type string `json:"type" datastore:"type"`
1440-
CreatedAt int64 `json:"created_at" datastore:"created_at"`
1441-
UpdatedAt int64 `json:"updated_at" datastore:"updated_at"`
1442-
MetaAccessAt int64 `json:"meta_access_at" datastore:"meta_access_at"`
1443-
DownloadAt int64 `json:"last_downloaded" datastore:"last_downloaded"`
1444-
Description string `json:"description" datastore:"description"`
1445-
ExpiresAt string `json:"expires_at" datastore:"expires_at"`
1446-
Status string `json:"status" datastore:"status"`
1447-
Filename string `json:"filename" datastore:"filename"`
1448-
URL string `json:"url" datastore:"org"`
1449-
OrgId string `json:"org_id" datastore:"org_id"`
1450-
WorkflowId string `json:"workflow_id" datastore:"workflow_id"`
1451-
Workflows []string `json:"workflows" datastore:"workflows"`
1452-
DownloadPath string `json:"download_path" datastore:"download_path"`
1453-
Md5sum string `json:"md5_sum" datastore:"md5_sum"`
1454-
Sha256sum string `json:"sha256_sum" datastore:"sha256_sum"`
1455-
FileSize int64 `json:"filesize" datastore:"filesize"`
1456-
Duplicate bool `json:"duplicate" datastore:"duplicate"`
1457-
Subflows []string `json:"subflows" datastore:"subflows"`
1458-
Tags []string `json:"tags" datastore:"tags"`
1459-
StorageArea string `json:"storage_area" datastore:"storage_area"`
1460-
Etag int `json:"etag" datastore:"etag"`
1461-
ContentType string `json:"content_type" datastore:"content_type"`
1462-
UpdatedBy string `json:"updated_by" datastore:"updated_by"`
1463-
CreatedBy string `json:"created_by" datastore:"created_by"`
1464-
Namespace string `json:"namespace" datastore:"namespace"`
1465-
Encrypted bool `json:"encrypted" datastore:"encrypted"`
1466-
IsEdited bool `json:"isedited" datastore:"isedited"`
1467-
LastEditor string `json:"lasteditor" datastore:"lasteditor"`
1468-
OriginalMd5sum string `json:"Originalmd5_sum" datastore:"Originalmd5_sum"`
1437+
Id string `json:"id" datastore:"id"`
1438+
ReferenceFileId string `json:"reference_file_id" datastore:"reference_file_id"`
1439+
Type string `json:"type" datastore:"type"`
1440+
CreatedAt int64 `json:"created_at" datastore:"created_at"`
1441+
UpdatedAt int64 `json:"updated_at" datastore:"updated_at"`
1442+
MetaAccessAt int64 `json:"meta_access_at" datastore:"meta_access_at"`
1443+
DownloadAt int64 `json:"last_downloaded" datastore:"last_downloaded"`
1444+
Description string `json:"description" datastore:"description"`
1445+
ExpiresAt string `json:"expires_at" datastore:"expires_at"`
1446+
Status string `json:"status" datastore:"status"`
1447+
Filename string `json:"filename" datastore:"filename"`
1448+
URL string `json:"url" datastore:"org"`
1449+
OrgId string `json:"org_id" datastore:"org_id"`
1450+
WorkflowId string `json:"workflow_id" datastore:"workflow_id"`
1451+
Workflows []string `json:"workflows" datastore:"workflows"`
1452+
DownloadPath string `json:"download_path" datastore:"download_path"`
1453+
Md5sum string `json:"md5_sum" datastore:"md5_sum"`
1454+
Sha256sum string `json:"sha256_sum" datastore:"sha256_sum"`
1455+
FileSize int64 `json:"filesize" datastore:"filesize"`
1456+
Duplicate bool `json:"duplicate" datastore:"duplicate"`
1457+
Subflows []string `json:"subflows" datastore:"subflows"`
1458+
Tags []string `json:"tags" datastore:"tags"`
1459+
StorageArea string `json:"storage_area" datastore:"storage_area"`
1460+
Etag int `json:"etag" datastore:"etag"`
1461+
ContentType string `json:"content_type" datastore:"content_type"`
1462+
UpdatedBy string `json:"updated_by" datastore:"updated_by"`
1463+
CreatedBy string `json:"created_by" datastore:"created_by"`
1464+
Namespace string `json:"namespace" datastore:"namespace"`
1465+
Encrypted bool `json:"encrypted" datastore:"encrypted"`
1466+
IsEdited bool `json:"isedited" datastore:"isedited"`
1467+
LastEditor string `json:"lasteditor" datastore:"lasteditor"`
1468+
OriginalMd5sum string `json:"Originalmd5_sum" datastore:"Originalmd5_sum"`
1469+
SuborgDistributed bool `json:"suborg_distributed" datastore:"suborg_distributed"`
14691470
}
14701471

14711472
type DisabledRules struct {
@@ -2715,13 +2716,15 @@ type DataToSend struct {
27152716
}
27162717

27172718
type BaseFile struct {
2718-
Name string `json:"name"`
2719-
ID string `json:"id"`
2720-
Type string `json:"type"`
2721-
UpdatedAt int64 `json:"updated_at"`
2722-
Md5Sum string `json:"md5_sum"`
2723-
Status string `json:"status"`
2724-
FileSize int64 `json:"filesize"`
2719+
Name string `json:"name"`
2720+
ID string `json:"id"`
2721+
Type string `json:"type"`
2722+
UpdatedAt int64 `json:"updated_at"`
2723+
Md5Sum string `json:"md5_sum"`
2724+
Status string `json:"status"`
2725+
FileSize int64 `json:"filesize"`
2726+
OrgId string `json:"org_id"`
2727+
SuborgDistributed bool `json:"suborg_distributed"`
27252728
}
27262729

27272730
type FileResponse struct {

0 commit comments

Comments
 (0)