close #11
This commit is contained in:
		
							parent
							
								
									69efc2d70f
								
							
						
					
					
						commit
						6df32165b1
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -81,7 +81,7 @@ $(document).on('ready pjax:success', function() { | ||||||
|         var value = $(this).val(), |         var value = $(this).val(), | ||||||
|           splited = value.split(":"), |           splited = value.split(":"), | ||||||
|           filename = "", |           filename = "", | ||||||
|           archtype = ""; |           archetype = ""; | ||||||
| 
 | 
 | ||||||
|         if (value == "") { |         if (value == "") { | ||||||
|           notification({ |           notification({ | ||||||
|  | @ -95,17 +95,17 @@ $(document).on('ready pjax:success', function() { | ||||||
|           filename = value; |           filename = value; | ||||||
|         } else if (splited.length == 2) { |         } else if (splited.length == 2) { | ||||||
|           filename = splited[0]; |           filename = splited[0]; | ||||||
|           archtype = splited[1]; |           archetype = splited[1]; | ||||||
|         } else { |         } else { | ||||||
|           notification({ |           notification({ | ||||||
|             text: "Hmm... I don't understand you. Try writing something like 'name[:archtype]'.", |             text: "Hmm... I don't understand you. Try writing something like 'name[:archetype]'.", | ||||||
|             type: 'error' |             type: 'error' | ||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         var content = '{"filename": "' + filename + '", "archtype": "' + archtype + '"}'; |         var content = '{"filename": "' + filename + '", "archetype": "' + archetype + '"}'; | ||||||
| 
 | 
 | ||||||
|         $.ajax({ |         $.ajax({ | ||||||
|           type: 'POST', |           type: 'POST', | ||||||
|  | @ -262,6 +262,10 @@ $(document).on('ready pjax:success', function() { | ||||||
|         type = "object"; |         type = "object"; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       if (title.is('h2')) { | ||||||
|  |         type = "object" | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       if (type == "object") { |       if (type == "object") { | ||||||
|         title.after('<input id="new" placeholder="Write the field name and press enter..."></input>'); |         title.after('<input id="new" placeholder="Write the field name and press enter..."></input>'); | ||||||
|         element = $("#new"); |         element = $("#new"); | ||||||
|  |  | ||||||
|  | @ -115,6 +115,7 @@ div[data-type="array-item"] { | ||||||
| 
 | 
 | ||||||
| label:hover > .actions, | label:hover > .actions, | ||||||
| h1:hover > .actions, | h1:hover > .actions, | ||||||
|  | h2:hover > .actions, | ||||||
| h3:hover > .actions, | h3:hover > .actions, | ||||||
| div[data-type="array-item"]:hover .actions { | div[data-type="array-item"]:hover .actions { | ||||||
|   opacity: .7; |   opacity: .7; | ||||||
|  |  | ||||||
							
								
								
									
										211
									
								
								browse/browse.go
								
								
								
								
							
							
						
						
									
										211
									
								
								browse/browse.go
								
								
								
								
							|  | @ -4,7 +4,6 @@ import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"log" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | @ -22,85 +21,157 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, c *config.Config) (int, e | ||||||
| 	// Removes the page main path from the URL
 | 	// Removes the page main path from the URL
 | ||||||
| 	r.URL.Path = strings.Replace(r.URL.Path, "/admin/browse", "", 1) | 	r.URL.Path = strings.Replace(r.URL.Path, "/admin/browse", "", 1) | ||||||
| 
 | 
 | ||||||
| 	// If the URL is blank now, replace it with a trailing slash
 | 	switch r.Method { | ||||||
| 	if r.URL.Path == "" { | 	case "DELETE": | ||||||
| 		r.URL.Path = "/" | 		return delete(w, r) | ||||||
|  | 	case "POST": | ||||||
|  | 		return post(w, r) | ||||||
|  | 	case "GET": | ||||||
|  | 		return get(w, r, c) | ||||||
|  | 	default: | ||||||
|  | 		return 400, nil | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	if r.Method == "DELETE" { | func delete(w http.ResponseWriter, r *http.Request) (int, error) { | ||||||
| 		// Remove both beginning and trailing slashes
 | 	// Remove both beginning and trailing slashes
 | ||||||
| 		r.URL.Path = strings.TrimPrefix(r.URL.Path, "/") | 	r.URL.Path = strings.TrimPrefix(r.URL.Path, "/") | ||||||
| 		r.URL.Path = strings.TrimSuffix(r.URL.Path, "/") | 	r.URL.Path = strings.TrimSuffix(r.URL.Path, "/") | ||||||
| 
 | 
 | ||||||
| 		// Check if the file or directory exists
 | 	// Check if the file or directory exists
 | ||||||
| 		if stat, err := os.Stat(r.URL.Path); err == nil { | 	if stat, err := os.Stat(r.URL.Path); err == nil { | ||||||
| 			var err error | 		var err error | ||||||
| 			// If it's dir, remove all of the content inside
 | 		// If it's dir, remove all of the content inside
 | ||||||
| 			if stat.IsDir() { | 		if stat.IsDir() { | ||||||
| 				err = os.RemoveAll(r.URL.Path) | 			err = os.RemoveAll(r.URL.Path) | ||||||
| 			} else { |  | ||||||
| 				err = os.Remove(r.URL.Path) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// Check for errors
 |  | ||||||
| 			if err != nil { |  | ||||||
| 				return 500, err |  | ||||||
| 			} |  | ||||||
| 		} else { | 		} else { | ||||||
| 			return 404, nil | 			err = os.Remove(r.URL.Path) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		w.Header().Set("Content-Type", "application/json") | 		// Check for errors
 | ||||||
| 		w.Write([]byte("{}")) |  | ||||||
| 	} else if r.Method == "POST" { |  | ||||||
| 		// Get the JSON information sent using a buffer
 |  | ||||||
| 		buffer := new(bytes.Buffer) |  | ||||||
| 		buffer.ReadFrom(r.Body) |  | ||||||
| 
 |  | ||||||
| 		// Creates the raw file "map" using the JSON
 |  | ||||||
| 		var info map[string]interface{} |  | ||||||
| 		json.Unmarshal(buffer.Bytes(), &info) |  | ||||||
| 
 |  | ||||||
| 		// Check if filename and archtype are specified in
 |  | ||||||
| 		// the request
 |  | ||||||
| 		if _, ok := info["filename"]; !ok { |  | ||||||
| 			return 400, errors.New("Filename not specified.") |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if _, ok := info["archtype"]; !ok { |  | ||||||
| 			return 400, errors.New("Archtype not specified.") |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} else { |  | ||||||
| 		functions := template.FuncMap{ |  | ||||||
| 			"CanBeEdited": utils.CanBeEdited, |  | ||||||
| 			"Defined":     utils.Defined, |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		tpl, err := utils.GetTemplate(r, functions, "browse") |  | ||||||
| 
 |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Print(err) | 			w.Write([]byte(err.Error())) | ||||||
| 			return 500, err | 			return 500, err | ||||||
| 		} | 		} | ||||||
| 
 | 	} else { | ||||||
| 		b := browse.Browse{ | 		return 404, nil | ||||||
| 			Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { |  | ||||||
| 				return 404, nil |  | ||||||
| 			}), |  | ||||||
| 			Root: "./", |  | ||||||
| 			Configs: []browse.Config{ |  | ||||||
| 				browse.Config{ |  | ||||||
| 					PathScope: "/", |  | ||||||
| 					Variables: c, |  | ||||||
| 					Template:  tpl, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			IgnoreIndexes: true, |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return b.ServeHTTP(w, r) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	w.Header().Set("Content-Type", "application/json") | ||||||
|  | 	w.Write([]byte("{}")) | ||||||
| 	return 200, nil | 	return 200, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func post(w http.ResponseWriter, r *http.Request) (int, error) { | ||||||
|  | 	// Remove both beginning  slashes
 | ||||||
|  | 	r.URL.Path = strings.TrimPrefix(r.URL.Path, "/") | ||||||
|  | 	// Get the JSON information sent using a buffer
 | ||||||
|  | 	buffer := new(bytes.Buffer) | ||||||
|  | 	buffer.ReadFrom(r.Body) | ||||||
|  | 
 | ||||||
|  | 	// Creates the raw file "map" using the JSON
 | ||||||
|  | 	var info map[string]interface{} | ||||||
|  | 	json.Unmarshal(buffer.Bytes(), &info) | ||||||
|  | 
 | ||||||
|  | 	// Check if filename and archetype are specified in
 | ||||||
|  | 	// the request
 | ||||||
|  | 	if _, ok := info["filename"]; !ok { | ||||||
|  | 		return 400, errors.New("Filename not specified.") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, ok := info["archetype"]; !ok { | ||||||
|  | 		return 400, errors.New("Archtype not specified.") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Sanitize the file name path
 | ||||||
|  | 	filename := info["filename"].(string) | ||||||
|  | 	filename = strings.TrimPrefix(filename, "/") | ||||||
|  | 	filename = strings.TrimSuffix(filename, "/") | ||||||
|  | 	filename = r.URL.Path + filename | ||||||
|  | 
 | ||||||
|  | 	// Check if the archetype is defined
 | ||||||
|  | 	if info["archetype"] != "" { | ||||||
|  | 		// Sanitize the archetype path
 | ||||||
|  | 		archetype := info["archetype"].(string) | ||||||
|  | 		archetype = strings.Replace(archetype, "/archetypes", "", 1) | ||||||
|  | 		archetype = strings.Replace(archetype, "archetypes", "", 1) | ||||||
|  | 		archetype = strings.TrimPrefix(archetype, "/") | ||||||
|  | 		archetype = strings.TrimSuffix(archetype, "/") | ||||||
|  | 		archetype = "archetypes/" + archetype | ||||||
|  | 
 | ||||||
|  | 		// Check if the archetype ending with .markdown exists
 | ||||||
|  | 		if _, err := os.Stat(archetype + ".markdown"); err == nil { | ||||||
|  | 			err = utils.CopyFile(archetype+".markdown", filename) | ||||||
|  | 
 | ||||||
|  | 			if err != nil { | ||||||
|  | 				w.Write([]byte(err.Error())) | ||||||
|  | 				return 500, err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			w.Header().Set("Location", "/admin/edit/"+filename) | ||||||
|  | 			w.Header().Set("Content-Type", "application/json") | ||||||
|  | 			w.Write([]byte("{}")) | ||||||
|  | 			return 201, nil | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Check if the archetype ending with .md exists
 | ||||||
|  | 		if _, err := os.Stat(archetype + ".md"); err == nil { | ||||||
|  | 			err = utils.CopyFile(archetype+".md", filename) | ||||||
|  | 
 | ||||||
|  | 			if err != nil { | ||||||
|  | 				w.Write([]byte(err.Error())) | ||||||
|  | 				return 500, err | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			w.Header().Set("Location", "/admin/edit/"+filename) | ||||||
|  | 			w.Header().Set("Content-Type", "application/json") | ||||||
|  | 			w.Write([]byte("{}")) | ||||||
|  | 			return 201, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	wf, err := os.Create(filename) | ||||||
|  | 
 | ||||||
|  | 	if err != nil { | ||||||
|  | 		w.Write([]byte(err.Error())) | ||||||
|  | 		return 500, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	defer wf.Close() | ||||||
|  | 
 | ||||||
|  | 	w.Header().Set("Location", "/admin/edit/"+filename) | ||||||
|  | 	w.Header().Set("Content-Type", "application/json") | ||||||
|  | 	w.Write([]byte("{}")) | ||||||
|  | 	return 200, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func get(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { | ||||||
|  | 	functions := template.FuncMap{ | ||||||
|  | 		"CanBeEdited": utils.CanBeEdited, | ||||||
|  | 		"Defined":     utils.Defined, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	tpl, err := utils.GetTemplate(r, functions, "browse") | ||||||
|  | 
 | ||||||
|  | 	if err != nil { | ||||||
|  | 		w.Write([]byte(err.Error())) | ||||||
|  | 		return 500, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b := browse.Browse{ | ||||||
|  | 		Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { | ||||||
|  | 			return 404, nil | ||||||
|  | 		}), | ||||||
|  | 		Root: "./", | ||||||
|  | 		Configs: []browse.Config{ | ||||||
|  | 			browse.Config{ | ||||||
|  | 				PathScope: "/", | ||||||
|  | 				Variables: c, | ||||||
|  | 				Template:  tpl, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		IgnoreIndexes: true, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return b.ServeHTTP(w, r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"log" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | @ -83,7 +82,7 @@ func servePost(w http.ResponseWriter, r *http.Request, filename string) (int, er | ||||||
| 		f = []byte(fString) | 		f = []byte(fString) | ||||||
| 
 | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Print(err) | 			w.Write([]byte(err.Error())) | ||||||
| 			return 500, err | 			return 500, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -106,7 +105,7 @@ func servePost(w http.ResponseWriter, r *http.Request, filename string) (int, er | ||||||
| 		jsonFrontmatter, err := json.Marshal(rawFile) | 		jsonFrontmatter, err := json.Marshal(rawFile) | ||||||
| 
 | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Print(err) | 			w.Write([]byte(err.Error())) | ||||||
| 			return 500, err | 			return 500, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -127,7 +126,7 @@ func servePost(w http.ResponseWriter, r *http.Request, filename string) (int, er | ||||||
| 	err := ioutil.WriteFile(filename, file, 0666) | 	err := ioutil.WriteFile(filename, file, 0666) | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Print(err) | 		w.Write([]byte(err.Error())) | ||||||
| 		return 500, err | 		return 500, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -145,14 +144,14 @@ func serveGet(w http.ResponseWriter, r *http.Request, c *config.Config, filename | ||||||
| 
 | 
 | ||||||
| 	// Check if the file exists. If it doesn't, send a "Not Found" message
 | 	// Check if the file exists. If it doesn't, send a "Not Found" message
 | ||||||
| 	if _, err := os.Stat(filename); os.IsNotExist(err) { | 	if _, err := os.Stat(filename); os.IsNotExist(err) { | ||||||
| 		log.Print(err) | 		w.Write([]byte(err.Error())) | ||||||
| 		return 404, nil | 		return 404, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Open the file and check if there was some error while opening
 | 	// Open the file and check if there was some error while opening
 | ||||||
| 	file, err := ioutil.ReadFile(filename) | 	file, err := ioutil.ReadFile(filename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Print(err) | 		w.Write([]byte(err.Error())) | ||||||
| 		return 500, err | 		return 500, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -173,7 +172,7 @@ func serveGet(w http.ResponseWriter, r *http.Request, c *config.Config, filename | ||||||
| 			buffer := bytes.NewBuffer(file) | 			buffer := bytes.NewBuffer(file) | ||||||
| 			file, err := parser.ReadFrom(buffer) | 			file, err := parser.ReadFrom(buffer) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				log.Print(err) | 				w.Write([]byte(err.Error())) | ||||||
| 				return 500, err | 				return 500, err | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -200,7 +199,7 @@ func serveGet(w http.ResponseWriter, r *http.Request, c *config.Config, filename | ||||||
| 
 | 
 | ||||||
| 		// Check if there were any errors
 | 		// Check if there were any errors
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Print(err) | 			w.Write([]byte(err.Error())) | ||||||
| 			return 500, err | 			return 500, err | ||||||
| 		} | 		} | ||||||
| 	default: | 	default: | ||||||
|  | @ -217,8 +216,9 @@ func serveGet(w http.ResponseWriter, r *http.Request, c *config.Config, filename | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	tpl, err := utils.GetTemplate(r, functions, "editor", "frontmatter") | 	tpl, err := utils.GetTemplate(r, functions, "editor", "frontmatter") | ||||||
|  | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Print(err) | 		w.Write([]byte(err.Error())) | ||||||
| 		return 500, err | 		return 500, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,7 +31,11 @@ | ||||||
|           <div id="preview-area" class="scroll hidden"></div> |           <div id="preview-area" class="scroll hidden"></div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="frontmatter scroll"> |         <div class="frontmatter scroll"> | ||||||
|           <h2>Metadata</h2> |           <h2>Metadata | ||||||
|  |             <span class="actions"> | ||||||
|  |               <button class="add"><i class="fa fa-plus"></i></button> | ||||||
|  |             </span> | ||||||
|  |           </h2> | ||||||
|           {{ template "frontmatter" .FrontMatter }} |           {{ template "frontmatter" .FrontMatter }} | ||||||
|         </div> |         </div> | ||||||
|         {{ end }} |         {{ end }} | ||||||
|  |  | ||||||
|  | @ -2,8 +2,10 @@ package utils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"io" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"os" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"text/template" | 	"text/template" | ||||||
|  | @ -12,6 +14,30 @@ import ( | ||||||
| 	"github.com/hacdias/caddy-hugo/assets" | 	"github.com/hacdias/caddy-hugo/assets" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // CopyFile is used to copy a file
 | ||||||
|  | func CopyFile(old, new string) error { | ||||||
|  | 	// Open the file and create a new one
 | ||||||
|  | 	r, err := os.Open(old) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer r.Close() | ||||||
|  | 
 | ||||||
|  | 	w, err := os.Create(new) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer w.Close() | ||||||
|  | 
 | ||||||
|  | 	// Copy the content
 | ||||||
|  | 	_, err = io.Copy(w, r) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // CanBeEdited checks if a filename has a supported extension
 | // CanBeEdited checks if a filename has a supported extension
 | ||||||
| func CanBeEdited(filename string) bool { | func CanBeEdited(filename string) bool { | ||||||
| 	extensions := [...]string{".markdown", ".md", | 	extensions := [...]string{".markdown", ".md", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue