@@ -18525,6 +18525,264 @@ func GetDocList(resp http.ResponseWriter, request *http.Request) {
1852518525 resp.Write(b)
1852618526}
1852718527
18528+ func GetArticles(resp http.ResponseWriter, request *http.Request) {
18529+ cors := HandleCors(resp, request)
18530+ if cors {
18531+ return
18532+ }
18533+
18534+ location := strings.Split(request.URL.String(), "/")
18535+ if len(location) < 5 {
18536+ resp.WriteHeader(404)
18537+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/articles/workflows.md"`)))
18538+ return
18539+ }
18540+
18541+ if strings.Contains(location[4], "?") {
18542+ location[4] = strings.Split(location[4], "?")[0]
18543+ }
18544+
18545+ ctx := GetContext(request)
18546+ downloadLocation, downloadOk := request.URL.Query()["location"]
18547+ version, versionOk := request.URL.Query()["version"]
18548+ cacheKey := fmt.Sprintf("articles_%s", location[4])
18549+ if downloadOk {
18550+ cacheKey = fmt.Sprintf("%s_%s", cacheKey, downloadLocation[0])
18551+ }
18552+
18553+ if versionOk {
18554+ cacheKey = fmt.Sprintf("%s_%s", cacheKey, version[0])
18555+ }
18556+
18557+ cache, err := GetCache(ctx, cacheKey)
18558+ if err == nil {
18559+ cacheData := []byte(cache.([]uint8))
18560+ resp.WriteHeader(200)
18561+ resp.Write(cacheData)
18562+ return
18563+ }
18564+
18565+ owner := "shuffle"
18566+ repo := "shuffle-docs"
18567+ path := "articles"
18568+ docPath := fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/master/%s/%s.md", owner, repo, path, location[4])
18569+
18570+ // FIXME: User controlled and dangerous (possibly). Uses Markdown on the frontend to render it
18571+ realPath := ""
18572+
18573+ newname := location[4]
18574+ if downloadOk {
18575+ if downloadLocation[0] == "openapi" {
18576+ newname = strings.ReplaceAll(strings.ToLower(location[4]), `%20`, "_")
18577+ docPath = fmt.Sprintf("https://raw.githubusercontent.com/Shuffle/openapi-apps/master/docs/%s.md", newname)
18578+ realPath = fmt.Sprintf("https://github.com/Shuffle/openapi-apps/blob/master/docs/%s.md", newname)
18579+
18580+ } else if downloadLocation[0] == "python" && versionOk {
18581+ // Apparently this uses dashes for no good reason?
18582+ // Should maybe move everything over to underscores later?
18583+ newname = strings.ReplaceAll(newname, `%20`, "-")
18584+ newname = strings.ReplaceAll(newname, ` `, "-")
18585+ newname = strings.ReplaceAll(newname, `_`, "-")
18586+ newname = strings.ToLower(newname)
18587+
18588+ if version[0] == "1.0.0" {
18589+ docPath = fmt.Sprintf("https://raw.githubusercontent.com/Shuffle/python-apps/master/%s/1.0.0/README.md", newname)
18590+ realPath = fmt.Sprintf("https://github.com/Shuffle/python-apps/blob/master/%s/1.0.0/README.md", newname)
18591+
18592+ log.Printf("[INFO] Should download python app for version %s: %s", version[0], docPath)
18593+
18594+ } else {
18595+ realPath = fmt.Sprintf("https://github.com/Shuffle/python-apps/blob/master/%s/README.md", newname)
18596+ docPath = fmt.Sprintf("https://raw.githubusercontent.com/Shuffle/python-apps/master/%s/README.md", newname)
18597+ }
18598+
18599+ }
18600+ }
18601+
18602+ //log.Printf("Docpath: %s", docPath)
18603+
18604+ httpClient := &http.Client{}
18605+ req, err := http.NewRequest(
18606+ "GET",
18607+ docPath,
18608+ nil,
18609+ )
18610+
18611+ if err != nil {
18612+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/articles/workflows.md"}`)))
18613+ resp.WriteHeader(404)
18614+ return
18615+ }
18616+
18617+ newresp, err := httpClient.Do(req)
18618+ if err != nil {
18619+ resp.WriteHeader(404)
18620+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/articles/workflows.md"}`)))
18621+ return
18622+ }
18623+
18624+ defer newresp.Body.Close()
18625+ body, err := ioutil.ReadAll(newresp.Body)
18626+ if err != nil {
18627+ resp.WriteHeader(500)
18628+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't parse data"}`)))
18629+ return
18630+ }
18631+
18632+ commitOptions := &github.CommitsListOptions{
18633+ Path: fmt.Sprintf("%s/%s.md", path, location[4]),
18634+ }
18635+
18636+ parsedLink := fmt.Sprintf("https://github.com/%s/%s/blob/master/%s/%s.md", owner, repo, path, location[4])
18637+ if len(realPath) > 0 {
18638+ parsedLink = realPath
18639+ }
18640+
18641+ client := github.NewClient(nil)
18642+ githubResp := GithubResp{
18643+ Name: location[4],
18644+ Contributors: []GithubAuthor{},
18645+ Edited: "",
18646+ ReadTime: len(body) / 10 / 250,
18647+ Link: parsedLink,
18648+ }
18649+
18650+ if githubResp.ReadTime == 0 {
18651+ githubResp.ReadTime = 1
18652+ }
18653+
18654+ info, _, err := client.Repositories.ListCommits(ctx, owner, repo, commitOptions)
18655+ if err != nil {
18656+ log.Printf("[WARNING] Failed getting commit info: %s", err)
18657+ } else {
18658+ //log.Printf("Info: %s", info)
18659+ for _, commit := range info {
18660+ //log.Printf("Commit: %s", commit.Author)
18661+ newAuthor := GithubAuthor{}
18662+ if commit.Author != nil && commit.Author.AvatarURL != nil {
18663+ newAuthor.ImageUrl = *commit.Author.AvatarURL
18664+ }
18665+
18666+ if commit.Author != nil && commit.Author.HTMLURL != nil {
18667+ newAuthor.Url = *commit.Author.HTMLURL
18668+ }
18669+
18670+ found := false
18671+ for _, contributor := range githubResp.Contributors {
18672+ if contributor.Url == newAuthor.Url {
18673+ found = true
18674+ break
18675+ }
18676+ }
18677+
18678+ if !found && len(newAuthor.Url) > 0 && len(newAuthor.ImageUrl) > 0 {
18679+ githubResp.Contributors = append(githubResp.Contributors, newAuthor)
18680+ }
18681+ }
18682+ }
18683+
18684+ type Result struct {
18685+ Success bool `json:"success"`
18686+ Reason string `json:"reason"`
18687+ Meta GithubResp `json:"meta"`
18688+ }
18689+
18690+ var result Result
18691+ result.Success = true
18692+ result.Meta = githubResp
18693+
18694+ result.Reason = string(body)
18695+ b, err := json.Marshal(result)
18696+ if err != nil {
18697+ http.Error(resp, err.Error(), 500)
18698+ return
18699+ }
18700+
18701+ err = SetCache(ctx, cacheKey, b, 180)
18702+ if err != nil {
18703+ log.Printf("[WARNING] Failed setting cache for articles %s: %s", location[4], err)
18704+ }
18705+
18706+ resp.WriteHeader(200)
18707+ resp.Write(b)
18708+ }
18709+
18710+ func GetArticlesList(resp http.ResponseWriter, request *http.Request) {
18711+ cors := HandleCors(resp, request)
18712+ if cors {
18713+ return
18714+ }
18715+
18716+ ctx := GetContext(request)
18717+ cacheKey := "articles_list"
18718+ cache, err := GetCache(ctx, cacheKey)
18719+ result := FileList{}
18720+ if err == nil {
18721+ cacheData := []byte(cache.([]uint8))
18722+ resp.WriteHeader(200)
18723+ resp.Write(cacheData)
18724+ return
18725+ }
18726+
18727+ client := github.NewClient(nil)
18728+ owner := "shuffle"
18729+ repo := "shuffle-docs"
18730+ path := "articles"
18731+ _, item1, _, err := client.Repositories.GetContents(ctx, owner, repo, path, nil)
18732+ if err != nil {
18733+ log.Printf("[WARNING] Failed getting articles list: %s", err)
18734+ resp.WriteHeader(500)
18735+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Error listing directory"}`)))
18736+ return
18737+ }
18738+
18739+ if len(item1) == 0 {
18740+ resp.WriteHeader(500)
18741+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No articles available."}`)))
18742+ return
18743+ }
18744+
18745+ names := []GithubResp{}
18746+ for _, item := range item1 {
18747+ if !strings.HasSuffix(*item.Name, "md") {
18748+ continue
18749+ }
18750+
18751+ // FIXME: Scuffed readtime calc
18752+ // Average word length = 5. Space = 1. 5+1 = 6 avg.
18753+ // Words = *item.Size/6/250
18754+ //250 = average read time / minute
18755+ // Doubling this for bloat removal in Markdown~
18756+ githubResp := GithubResp{
18757+ Name: (*item.Name)[0 : len(*item.Name)-3],
18758+ Contributors: []GithubAuthor{},
18759+ Edited: "",
18760+ ReadTime: *item.Size / 6 / 250,
18761+ Link: fmt.Sprintf("https://github.com/%s/%s/blob/master/%s/%s", owner, repo, path, *item.Name),
18762+ }
18763+
18764+ names = append(names, githubResp)
18765+ }
18766+
18767+ //log.Printf(names)
18768+ result.Success = true
18769+ result.Reason = "Success"
18770+ result.List = names
18771+ b, err := json.Marshal(result)
18772+ if err != nil {
18773+ http.Error(resp, err.Error(), 500)
18774+ return
18775+ }
18776+
18777+ err = SetCache(ctx, cacheKey, b, 300)
18778+ if err != nil {
18779+ log.Printf("[WARNING] Failed setting cache for cachekey %s: %s", cacheKey, err)
18780+ }
18781+
18782+ resp.WriteHeader(200)
18783+ resp.Write(b)
18784+ }
18785+
1852818786func md5sum(data []byte) string {
1852918787 hasher := md5.New()
1853018788 hasher.Write(data)
0 commit comments