|
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
const (
publishDateLayout = "200601021504"
)
type Account struct {
Username string `json:username`
Passphrase string `json:passphrase`
}
func getAccounts() ([]Account, error) {
file := UserFile
// Check to see if the file exists
if _, err := os.Stat(file); os.IsNotExist(err) {
return []Account{}, nil
}
// Open the file
fi, err := os.Open(file)
if err != nil {
return nil, err
}
// Read all of its contents
raw, err := ioutil.ReadAll(fi)
if len(raw) == 0 {
return []Account{}, nil
}
// Translate the JSON to internal structures
var accounts []Account
err = json.Unmarshal(raw, &accounts)
if err != nil {
return nil, err
}
fi.Close()
return accounts, nil
}
func (a *Account) Validate() (bool, error) {
file := UserFile
// Determine if the "users" file exists
// Attempt to create the file if it does not
if _, err := os.Stat(file); os.IsNotExist(err) {
_, err = os.Create(file)
if err != nil {
return false, err
}
}
// Get a list of current accounts
accounts, err := getAccounts()
if err != nil {
return false, err
}
// Search if an account and passphrase match is found
for _, x := range accounts {
if x.Username == a.Username && x.Passphrase == a.Passphrase {
return true, nil
}
}
return false, nil
}
func (a *Account) Create() error {
// Ensure there are no accounts of that name already
valid, err := a.Validate()
if err != nil {
return err
}
if valid {
return errors.New("Account already exists")
}
// Create directory structure
baseDir := os.Getenv("LOOP_DATA")
userDir := strings.ToLower(a.Username)
s := string(filepath.Separator)
paths := []string{"content", "blog", "calendar"}
for _, p := range paths {
err = os.MkdirAll(baseDir+s+userDir+s+p, 0755)
if err != nil {
return err
}
}
// Add the account to all of the accounts
accounts, err := getAccounts()
if err != nil {
return err
}
accounts = append(accounts, *a)
// Create user entry in "users" file
// Marshal the JSON
marshalled, err := json.Marshal(accounts)
if err != nil {
return err
}
// Write to the file
fi, err := os.OpenFile(UserFile, os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
return err
}
_, err = fi.Write(marshalled)
if err != nil {
return err
}
fi.Close()
return nil
}
func (a *Account) Delete() error {
// Ensure there are no accounts of that name already
valid, err := a.Validate()
if err != nil {
return err
}
if !valid {
return errors.New("Account does not exist")
}
// Remove user entry in "users" file
accounts, err := getAccounts()
if err != nil {
return err
}
for i, account := range accounts {
if account.Username == a.Username {
accounts = append(accounts[:i], accounts[i+1:]...)
break
}
}
marshalled, err := json.Marshal(accounts)
if err != nil {
return err
}
// Write to the file
fi, err := os.OpenFile(UserFile, os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
return err
}
_, err = fi.Write(marshalled)
if err != nil {
return err
}
fi.Close()
// Delete directory structure
baseDir := os.Getenv("LOOP_DATA")
userDir := strings.ToLower(a.Username)
s := string(filepath.Separator)
err = os.RemoveAll(baseDir + s + userDir)
if err != nil {
return err
}
return nil
}
func (a *Account) Add(content, filename string, file []byte) (string, error) {
if filename == "" {
return "", errors.New("Missing filename")
}
valid, err := a.Validate()
if err != nil {
return "", err
}
if !valid {
return "", errors.New("Account does not exist")
}
// Get basic information needed
baseDir := os.Getenv("LOOP_DATA")
userDir := strings.ToLower(a.Username)
s := string(filepath.Separator)
// Create new content directory if necessary
if content == "" {
content = fmt.Sprintf("%x", hash(userDir+time.Now().Format(publishDateLayout), salt()))
}
// Create new content directory
contentPath := baseDir + s + userDir + s + "content" + s + content
if _, err := os.Stat(contentPath); os.IsNotExist(err) {
err = os.MkdirAll(contentPath, 0755)
if err != nil {
return "", err
}
}
// Check if filename already exists
filePath := contentPath + s + filename
if _, err := os.Stat(filePath); os.IsExist(err) {
return filePath, err
}
// Write file to content directory
fi, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
return filePath, err
}
_, err = fi.Write(file)
if err != nil {
return filePath, err
}
fi.Close()
return filePath, nil
}
func (a *Account) Publish(title, content string, date time.Time) error {
valid, err := a.Validate()
if err != nil {
return err
}
if !valid {
return errors.New("Account does not exist")
}
prettyTitle := strings.ToLower(strings.Replace(title, " ", "-", -1))
baseDir := os.Getenv("LOOP_DATA")
userDir := strings.ToLower(a.Username)
s := string(filepath.Separator)
contentPath := baseDir + s + userDir + s + "content" + s + content
publishPath := baseDir + s + userDir + s + "blog" + s + date.Format(publishDateLayout) + "-" + prettyTitle
// Check if the content exists
if _, err := os.Stat(contentPath); os.IsNotExist(err) {
return err
}
// Check if symlink already exists
if _, err := os.Stat(publishPath); os.IsExist(err) {
return err
}
// Create symbolic link in "blog" directory referencing content directory
err = os.Symlink(contentPath, publishPath)
if err != nil {
return err
}
return nil
}
|