1// Copyright 2014 The Gogs Authors. All rights reserved. 2// Use of this source code is governed by a MIT-style 3// license that can be found in the LICENSE file. 4 5package misc 6 7import ( 8 "net/http" 9 "strings" 10 11 "code.gitea.io/gitea/modules/context" 12 "code.gitea.io/gitea/modules/markup" 13 "code.gitea.io/gitea/modules/markup/markdown" 14 "code.gitea.io/gitea/modules/setting" 15 api "code.gitea.io/gitea/modules/structs" 16 "code.gitea.io/gitea/modules/util" 17 "code.gitea.io/gitea/modules/web" 18 19 "mvdan.cc/xurls/v2" 20) 21 22// Markdown render markdown document to HTML 23func Markdown(ctx *context.APIContext) { 24 // swagger:operation POST /markdown miscellaneous renderMarkdown 25 // --- 26 // summary: Render a markdown document as HTML 27 // parameters: 28 // - name: body 29 // in: body 30 // schema: 31 // "$ref": "#/definitions/MarkdownOption" 32 // consumes: 33 // - application/json 34 // produces: 35 // - text/html 36 // responses: 37 // "200": 38 // "$ref": "#/responses/MarkdownRender" 39 // "422": 40 // "$ref": "#/responses/validationError" 41 42 form := web.GetForm(ctx).(*api.MarkdownOption) 43 44 if ctx.HasAPIError() { 45 ctx.Error(http.StatusUnprocessableEntity, "", ctx.GetErrMsg()) 46 return 47 } 48 49 if len(form.Text) == 0 { 50 _, _ = ctx.Write([]byte("")) 51 return 52 } 53 54 switch form.Mode { 55 case "comment": 56 fallthrough 57 case "gfm": 58 urlPrefix := form.Context 59 meta := map[string]string{} 60 if !strings.HasPrefix(setting.AppSubURL+"/", urlPrefix) { 61 // check if urlPrefix is already set to a URL 62 linkRegex, _ := xurls.StrictMatchingScheme("https?://") 63 m := linkRegex.FindStringIndex(urlPrefix) 64 if m == nil { 65 urlPrefix = util.URLJoin(setting.AppURL, form.Context) 66 } 67 } 68 if ctx.Repo != nil && ctx.Repo.Repository != nil { 69 // "gfm" = Github Flavored Markdown - set this to render as a document 70 if form.Mode == "gfm" { 71 meta = ctx.Repo.Repository.ComposeDocumentMetas() 72 } else { 73 meta = ctx.Repo.Repository.ComposeMetas() 74 } 75 } 76 if form.Mode == "gfm" { 77 meta["mode"] = "document" 78 } 79 80 if err := markdown.Render(&markup.RenderContext{ 81 URLPrefix: urlPrefix, 82 Metas: meta, 83 IsWiki: form.Wiki, 84 }, strings.NewReader(form.Text), ctx.Resp); err != nil { 85 ctx.InternalServerError(err) 86 return 87 } 88 default: 89 if err := markdown.RenderRaw(&markup.RenderContext{ 90 URLPrefix: form.Context, 91 }, strings.NewReader(form.Text), ctx.Resp); err != nil { 92 ctx.InternalServerError(err) 93 return 94 } 95 } 96} 97 98// MarkdownRaw render raw markdown HTML 99func MarkdownRaw(ctx *context.APIContext) { 100 // swagger:operation POST /markdown/raw miscellaneous renderMarkdownRaw 101 // --- 102 // summary: Render raw markdown as HTML 103 // parameters: 104 // - name: body 105 // in: body 106 // description: Request body to render 107 // required: true 108 // schema: 109 // type: string 110 // consumes: 111 // - text/plain 112 // produces: 113 // - text/html 114 // responses: 115 // "200": 116 // "$ref": "#/responses/MarkdownRender" 117 // "422": 118 // "$ref": "#/responses/validationError" 119 defer ctx.Req.Body.Close() 120 if err := markdown.RenderRaw(&markup.RenderContext{}, ctx.Req.Body, ctx.Resp); err != nil { 121 ctx.InternalServerError(err) 122 return 123 } 124} 125