Example #1
0
// API function to get a post by id
func getApiPostHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		id := params["id"]
		// Get post
		postId, err := strconv.ParseInt(id, 10, 64)
		if err != nil || postId < 1 {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		post, err := database.RetrievePostById(postId)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		json, err := json.Marshal(postToJson(post))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #2
0
// API function to delete an image by its filename.
func deleteApiImageHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" { // TODO: Check if the user has permissions to delete the image
		// Get the file name from the json data
		decoder := json.NewDecoder(r.Body)
		var json JsonImage
		err := decoder.Decode(&json)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = filepath.Walk(filenames.ImagesFilepath, func(filePath string, info os.FileInfo, err error) error {
			if !info.IsDir() && filepath.Base(filePath) == filepath.Base(json.Filename) {
				err := os.Remove(filePath)
				if err != nil {
					return err
				}
			}
			return nil
		})
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Image deleted!"))
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #3
0
// API function to get all posts by pages
func apiPostsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		number := params["number"]
		page, err := strconv.Atoi(number)
		if err != nil || page < 1 {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		postsPerPage := int64(15)
		posts, err := database.RetrievePostsForApi(postsPerPage, ((int64(page) - 1) * postsPerPage))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		json, err := json.Marshal(postsToJson(posts))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #4
0
// API function to update blog settings
func patchApiBlogHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		userId, err := getUserId(userName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		decoder := json.NewDecoder(r.Body)
		var json JsonBlog
		err = decoder.Decode(&json)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Make sure postPerPage is over 0
		if json.PostsPerPage < 1 {
			json.PostsPerPage = 1
		}
		// Remove blog url in front of navigation urls
		for index, _ := range json.NavigationItems {
			if strings.HasPrefix(json.NavigationItems[index].Url, json.Url) {
				json.NavigationItems[index].Url = strings.Replace(json.NavigationItems[index].Url, json.Url, "", 1)
				// If we removed the blog url, there should be a / in front of the url
				if !strings.HasPrefix(json.NavigationItems[index].Url, "/") {
					json.NavigationItems[index].Url = "/" + json.NavigationItems[index].Url
				}
			}
		}
		// Retrieve old blog settings for comparison
		blog, err := database.RetrieveBlog()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tempBlog := structure.Blog{Url: []byte(configuration.Config.Url), Title: []byte(json.Title), Description: []byte(json.Description), Logo: []byte(json.Logo), Cover: []byte(json.Cover), AssetPath: []byte("/assets/"), PostCount: blog.PostCount, PostsPerPage: json.PostsPerPage, ActiveTheme: json.ActiveTheme, NavigationItems: json.NavigationItems}
		err = methods.UpdateBlog(&tempBlog, userId)
		// Check if active theme setting has been changed, if so, generate templates from new theme
		if tempBlog.ActiveTheme != blog.ActiveTheme {
			err = templates.Generate()
			if err != nil {
				// If there's an error while generating the new templates, the whole program must be stopped.
				log.Fatal("Fatal error: Template data couldn't be generated from theme files: " + err.Error())
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Blog settings updated!"))
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #5
0
// API function to upload images
func apiUploadHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		// Create multipart reader
		reader, err := r.MultipartReader()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Slice to hold all paths to the files
		allFilePaths := make([]string, 0)
		// Copy each part to destination.
		for {
			part, err := reader.NextPart()
			if err == io.EOF {
				break
			}
			// If part.FileName() is empty, skip this iteration.
			if part.FileName() == "" {
				continue
			}
			// Folder structure: year/month/randomname
			filePath := filepath.Join(filenames.ImagesFilepath, time.Now().Format("2006"), time.Now().Format("01"))
			if os.MkdirAll(filePath, 0777) != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			dst, err := os.Create(filepath.Join(filePath, strconv.FormatInt(time.Now().Unix(), 10)+"_"+uuid.Formatter(uuid.NewV4(), uuid.Clean)+filepath.Ext(part.FileName())))
			defer dst.Close()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if _, err := io.Copy(dst, part); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			// Rewrite to file path on server
			filePath = strings.Replace(dst.Name(), filenames.ImagesFilepath, "/images", 1)
			// Make sure to always use "/" as path separator (to make a valid url that we can use on the blog)
			filePath = filepath.ToSlash(filePath)
			allFilePaths = append(allFilePaths, filePath)
		}
		json, err := json.Marshal(allFilePaths)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #6
0
// Function to serve files belonging to the admin interface.
func adminFileHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		// Get arguments (files)
		http.ServeFile(w, r, filepath.Join(filenames.AdminFilepath, params["filepath"]))
		return
	} else {
		http.NotFound(w, r)
		return
	}
}
Example #7
0
// API function to get all images by pages
func apiImagesHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		number := params["number"]
		page, err := strconv.Atoi(number)
		if err != nil || page < 1 {
			http.Error(w, "Not a valid api function!", http.StatusInternalServerError)
			return
		}
		images := make([]string, 0)
		// Walk all files in images folder
		err = filepath.Walk(filenames.ImagesFilepath, func(filePath string, info os.FileInfo, err error) error {
			if !info.IsDir() && (strings.EqualFold(filepath.Ext(filePath), ".jpg") || strings.EqualFold(filepath.Ext(filePath), ".jpeg") || strings.EqualFold(filepath.Ext(filePath), ".gif") || strings.EqualFold(filepath.Ext(filePath), ".png") || strings.EqualFold(filepath.Ext(filePath), ".svg")) {
				// Rewrite to file path on server
				filePath = strings.Replace(filePath, filenames.ImagesFilepath, "/images", 1)
				// Make sure to always use "/" as path separator (to make a valid url that we can use on the blog)
				filePath = filepath.ToSlash(filePath)
				// Prepend file to slice (thus reversing the order)
				images = append([]string{filePath}, images...)
			}
			return nil
		})
		if len(images) == 0 {
			// Write empty json array
			w.Header().Set("Content-Type", "application/json")
			w.Write([]byte("[]"))
			return
		}
		imagesPerPage := 15
		start := (page * imagesPerPage) - imagesPerPage
		end := page * imagesPerPage
		if start > (len(images) - 1) {
			// Write empty json array
			w.Header().Set("Content-Type", "application/json")
			w.Write([]byte("[]"))
			return
		}
		if end > len(images) {
			end = len(images)
		}
		json, err := json.Marshal(images[start:end])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #8
0
// Function to route the /admin/ url accordingly. (Is user logged in? Is at least one user registered?)
func adminHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	if database.RetrieveUsersCount() == 0 {
		http.Redirect(w, r, "/admin/register/", 302)
		return
	} else {
		userName := authentication.GetUserName(r)
		if userName != "" {
			http.ServeFile(w, r, filepath.Join(filenames.AdminFilepath, "admin.html"))
			return
		} else {
			http.Redirect(w, r, "/admin/login/", 302)
			return
		}
	}
}
Example #9
0
// API function to update a post.
func patchApiPostHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		userId, err := getUserId(userName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Update post
		decoder := json.NewDecoder(r.Body)
		var json JsonPost
		err = decoder.Decode(&json)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		var postSlug string
		// Get current slug of post
		post, err := database.RetrievePostById(json.Id)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if json.Slug != post.Slug { // Check if user has submitted a custom slug
			postSlug = slug.Generate(json.Slug, "posts")
		} else {
			postSlug = post.Slug
		}
		currentTime := time.Now()
		*post = structure.Post{Id: json.Id, Title: []byte(json.Title), Slug: postSlug, Markdown: []byte(json.Markdown), Html: conversion.GenerateHtmlFromMarkdown([]byte(json.Markdown)), IsFeatured: json.IsFeatured, IsPage: json.IsPage, IsPublished: json.IsPublished, Image: []byte(json.Image), Date: &currentTime, Tags: methods.GenerateTagsFromCommaString(json.Tags), Author: &structure.User{Id: userId}}
		err = methods.UpdatePost(post)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Post updated!"))
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #10
0
// API function to get blog settings
func getApiBlogHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		// Read lock the global blog
		methods.Blog.RLock()
		defer methods.Blog.RUnlock()
		blogJson := blogToJson(methods.Blog)
		json, err := json.Marshal(blogJson)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #11
0
// API function to get the id of the currently authenticated user
func getApiUserIdHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		userId, err := getUserId(userName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		jsonUserId := JsonUserId{Id: userId}
		json, err := json.Marshal(jsonUserId)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #12
0
// API function to delete a post by id.
func deleteApiPostHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		id := params["id"]
		// Delete post
		postId, err := strconv.ParseInt(id, 10, 64)
		if err != nil || postId < 1 {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = methods.DeletePost(postId)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Post deleted!"))
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #13
0
// API function to get user settings
func getApiUserHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		userId, err := getUserId(userName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		id := params["id"]
		userIdToGet, err := strconv.ParseInt(id, 10, 64)
		if err != nil || userIdToGet < 1 {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		} else if userIdToGet != userId { // Make sure the authenticated user is only accessing his/her own data. TODO: Make sure the user is admin when multiple users have been introduced
			http.Error(w, "You don't have permission to access this data.", http.StatusForbidden)
			return
		}
		user, err := database.RetrieveUser(userIdToGet)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		userJson := userToJson(user)
		json, err := json.Marshal(userJson)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write(json)
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}
Example #14
0
// API function to patch user settings
func patchApiUserHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	userName := authentication.GetUserName(r)
	if userName != "" {
		userId, err := getUserId(userName)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		decoder := json.NewDecoder(r.Body)
		var json JsonUser
		err = decoder.Decode(&json)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Make sure user id is over 0
		if json.Id < 1 {
			http.Error(w, "Wrong user id.", http.StatusInternalServerError)
			return
		} else if userId != json.Id { // Make sure the authenticated user is only changing his/her own data. TODO: Make sure the user is admin when multiple users have been introduced
			http.Error(w, "You don't have permission to change this data.", http.StatusInternalServerError)
			return
		}
		// Get old user data to compare
		tempUser, err := database.RetrieveUser(json.Id)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// Make sure user email is provided
		if json.Email == "" {
			json.Email = string(tempUser.Email)
		}
		// Make sure user name is provided
		if json.Name == "" {
			json.Name = string(tempUser.Name)
		}
		// Make sure user slug is provided
		if json.Slug == "" {
			json.Slug = tempUser.Slug
		}
		// Check if new name is already taken
		if json.Name != string(tempUser.Name) {
			_, err = database.RetrieveUserByName([]byte(json.Name))
			if err == nil {
				// The new user name is already taken. Assign the old name.
				// TODO: Return error that will be displayed in the admin interface.
				json.Name = string(tempUser.Name)
			}
		}
		// Check if new slug is already taken
		if json.Slug != tempUser.Slug {
			_, err = database.RetrieveUserBySlug(json.Slug)
			if err == nil {
				// The new user slug is already taken. Assign the old slug.
				// TODO: Return error that will be displayed in the admin interface.
				json.Slug = tempUser.Slug
			}
		}
		user := structure.User{Id: json.Id, Name: []byte(json.Name), Slug: json.Slug, Email: []byte(json.Email), Image: []byte(json.Image), Cover: []byte(json.Cover), Bio: []byte(json.Bio), Website: []byte(json.Website), Location: []byte(json.Location)}
		err = methods.UpdateUser(&user, userId)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if json.Password != "" && (json.Password == json.PasswordRepeated) { // Update password if a new one was submitted
			encryptedPassword, err := authentication.EncryptPassword(json.Password)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			err = database.UpdateUserPassword(user.Id, encryptedPassword, time.Now(), json.Id)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		// Check if the user name was changed. If so, update the session cookie to the new user name.
		if json.Name != string(tempUser.Name) {
			logInUser(json.Name, w)
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("User settings updated!"))
		return
	} else {
		http.Error(w, "Not logged in!", http.StatusInternalServerError)
		return
	}
}