<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/jaracil/ei"
	. "github.com/jaracil/nexus/log"
	"github.com/sirupsen/logrus"
	r "gopkg.in/rethinkdb/rethinkdb-go.v5"
)

type Session struct {
	Id     string `rethinkdb:"id"`
	Kick   bool   `rethinkdb:"kick"`
	Reload bool   `rethinkdb:"reload"`
}

type SessionFeed struct {
	Old *Session `rethinkdb:"old_val"`
	New *Session `rethinkdb:"new_val"`
}

func sessionTrack() {
	defer exit("sessions change-feed error")
	for retry := 0; retry < 10; retry++ {
		iter, err := r.Table("sessions").
			Between(nodeId, nodeId+"\uffff").
			Changes(r.ChangesOpts{IncludeInitial: true, Squash: false}).
			Pluck(map[string]interface{}{
				"new_val": []string{"id", "kick", "reload"},
				"old_val": []string{"id"}}).
			Run(db)
		if err != nil {
			Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Errorf("Error opening sessionTrack iterator")
			time.Sleep(time.Second)
			continue
		}
		retry = 0
		for {
			sf := &SessionFeed{}
			if !iter.Next(sf) {
				Log.WithFields(logrus.Fields{
					"error": iter.Err().Error(),
				}).Errorf("Error processing sessionTrack feed")
				iter.Close()
				break
			}
			if sf.New == nil { // session closed
				sesNotify.Unregister(sf.Old.Id)
				continue
			}
			sesNotify.Notify(sf.New.Id, sf.New)
		}
	}
}

func (nc *NexusConn) handleSessionReq(req *JsonRpcReq) {
	switch req.Method {
	case "sys.session.list":
		prefix, depth, filter, limit, skip := getListParams(req.Params)

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@sys.session.list").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		term := getListTerm("sessions", "users", "user", prefix, depth, filter, limit, skip)

		term = term.
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("user"),
					"connid":        row.Field("id"),
					"nodeid":        row.Field("nodeId"),
					"remoteAddress": row.Field("remoteAddress"),
					"creationTime":  row.Field("creationTime"),
					"protocol":      row.Field("protocol")}
			}).
			Group("user").
			Pluck("connid", "nodeid", "remoteAddress", "creationTime", "protocol").
			Filter(r.Row.Field("protocol").Ne("internal"))

		cur, err := term.Ungroup().
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("group"),
					"sessions": row.Field("reduction"),
					"n":        row.Field("reduction").Count()}
			}).Run(db)
		defer cur.Close()
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var all []interface{}
		if err := cur.All(&all); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		req.Result(all)

	case "sys.session.count":
		prefix := getPrefixParam(req.Params)
		filter := ei.N(req.Params).M("filter").StringZ()
		countSubprefixes := ei.N(req.Params).M("subprefixes").BoolZ()

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@sys.session.count").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		var term r.Term
		if countSubprefixes {
			if prefix == "" {
				term = r.Table("sessions").Filter(r.Row.Field("protocol").Ne("internal"))
				if filter != "" {
					term = term.Filter(r.Row.Field("user").Match(filter))
				}
				term = term.Group(r.Row.Field("user").Match("^([^.]*)(?:[.][^.]*)*$").Field("groups").Nth(0).Field("str")).Count().Ungroup().Map(func(t r.Term) r.Term {
					return r.Branch(t.HasFields("group"), r.Object("prefix", t.Field("group"), "count", t.Field("reduction")), r.Object("prefix", "", "count", t.Field("reduction")))
				})
			} else {
				term = r.Table("sessions").GetAllByIndex("users", prefix).Union(r.Table("sessions").Between(prefix+".", prefix+".\uffff", r.BetweenOpts{Index: "users"})).Filter(r.Row.Field("protocol").Ne("internal"))
				if filter != "" {
					term = term.Filter(r.Row.Field("user").Match(filter))
				}
				term = term.Group(r.Row.Field("user").Match(fmt.Sprintf("^%s[.]([^.]*)(?:[.][^.]*)*$", prefix)).Field("groups").Nth(0).Field("str")).Count().Ungroup().Map(func(t r.Term) r.Term {
					return r.Branch(t.HasFields("group"), r.Object("prefix", r.Add(prefix+".", t.Field("group")), "count", t.Field("reduction")), r.Object("prefix", prefix, "count", t.Field("reduction")))
				})
			}
		} else {
			if prefix == "" {
				term = r.Table("sessions").Filter(r.Row.Field("protocol").Ne("internal"))
			} else {
				term = r.Table("sessions").GetAllByIndex("users", prefix).Union(r.Table("sessions").Between(prefix+".", prefix+".\uffff", r.BetweenOpts{Index: "users"})).Filter(r.Row.Field("protocol").Ne("internal"))
			}
			if filter != "" {
				term = term.Filter(r.Row.Field("user").Match(filter))
			}
			term = term.Count()
		}

		cur, err := term.Run(db)
		defer cur.Close()
		if err != nil {
			req.Error(ErrInternal, err.Error(), nil)
			return
		}
		var all []interface{}
		if err := cur.All(&all); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		if countSubprefixes {
			req.Result(all)
		} else if len(all) > 0 {
			req.Result(ei.M{"count": all[0]})
		} else {
			req.Result(ei.M{"count": 0})
		}

	case "sys.session.kick":
		fallthrough
	case "sys.session.reload":
		action := req.Method[12:]
		prefix := ei.N(req.Params).M("connid").StringZ()

		if len(prefix) < 16 {
			req.Error(ErrInvalidParams, "", nil)
			return
		}

		connuser, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff").
			Pluck("user").
			Run(db)
		defer connuser.Close()
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var userd interface{}
		if err := connuser.One(&userd); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		user := ei.N(userd).M("user").Lower().StringZ()
		tags := nc.getTags(user)
		if !(ei.N(tags).M("@sys.session."+action).BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		Log.WithFields(logrus.Fields{
			"connid":  nc.connId,
			"action":  action,
			"session": prefix,
			"by":      user,
		}).Printf("Session %s", action)

		res, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff").
			Update(ei.M{action: true}).
			RunWrite(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		req.Result(ei.M{action + "ed": res.Replaced})

	default:
		req.Error(ErrMethodNotFound, "", nil)
	}
}
<commit_msg>Avoid panic if the sessions track finds no sessions<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/jaracil/ei"
	. "github.com/jaracil/nexus/log"
	"github.com/sirupsen/logrus"
	r "gopkg.in/rethinkdb/rethinkdb-go.v5"
)

type Session struct {
	Id     string `rethinkdb:"id"`
	Kick   bool   `rethinkdb:"kick"`
	Reload bool   `rethinkdb:"reload"`
}

type SessionFeed struct {
	Old *Session `rethinkdb:"old_val"`
	New *Session `rethinkdb:"new_val"`
}

func sessionTrack() {
	defer exit("sessions change-feed error")
	for retry := 0; retry < 10; retry++ {
		iter, err := r.Table("sessions").
			Between(nodeId, nodeId+"\uffff").
			Changes(r.ChangesOpts{IncludeInitial: true, Squash: false}).
			Pluck(map[string]interface{}{
				"new_val": []string{"id", "kick", "reload"},
				"old_val": []string{"id"}}).
			Run(db)
		if err != nil {
			Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Errorf("Error opening sessionTrack iterator")
			time.Sleep(time.Second)
			continue
		}
		retry = 0
		for {
			sf := &SessionFeed{}
			if !iter.Next(sf) {
				Log.WithFields(logrus.Fields{
					"error": iter.Err().Error(),
				}).Errorf("Error processing sessionTrack feed")
				iter.Close()
				break
			}
			if sf.New == nil { // session closed
				if sf.Old == nil { // there is no sessions
					continue
				}
				sesNotify.Unregister(sf.Old.Id)
				continue
			}
			sesNotify.Notify(sf.New.Id, sf.New)
		}
	}
}

func (nc *NexusConn) handleSessionReq(req *JsonRpcReq) {
	switch req.Method {
	case "sys.session.list":
		prefix, depth, filter, limit, skip := getListParams(req.Params)

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@sys.session.list").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		term := getListTerm("sessions", "users", "user", prefix, depth, filter, limit, skip)

		term = term.
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("user"),
					"connid":        row.Field("id"),
					"nodeid":        row.Field("nodeId"),
					"remoteAddress": row.Field("remoteAddress"),
					"creationTime":  row.Field("creationTime"),
					"protocol":      row.Field("protocol")}
			}).
			Group("user").
			Pluck("connid", "nodeid", "remoteAddress", "creationTime", "protocol").
			Filter(r.Row.Field("protocol").Ne("internal"))

		cur, err := term.Ungroup().
			Map(func(row r.Term) interface{} {
				return ei.M{"user": row.Field("group"),
					"sessions": row.Field("reduction"),
					"n":        row.Field("reduction").Count()}
			}).Run(db)
		defer cur.Close()
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var all []interface{}
		if err := cur.All(&all); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		req.Result(all)

	case "sys.session.count":
		prefix := getPrefixParam(req.Params)
		filter := ei.N(req.Params).M("filter").StringZ()
		countSubprefixes := ei.N(req.Params).M("subprefixes").BoolZ()

		tags := nc.getTags(prefix)
		if !(ei.N(tags).M("@sys.session.count").BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		var term r.Term
		if countSubprefixes {
			if prefix == "" {
				term = r.Table("sessions").Filter(r.Row.Field("protocol").Ne("internal"))
				if filter != "" {
					term = term.Filter(r.Row.Field("user").Match(filter))
				}
				term = term.Group(r.Row.Field("user").Match("^([^.]*)(?:[.][^.]*)*$").Field("groups").Nth(0).Field("str")).Count().Ungroup().Map(func(t r.Term) r.Term {
					return r.Branch(t.HasFields("group"), r.Object("prefix", t.Field("group"), "count", t.Field("reduction")), r.Object("prefix", "", "count", t.Field("reduction")))
				})
			} else {
				term = r.Table("sessions").GetAllByIndex("users", prefix).Union(r.Table("sessions").Between(prefix+".", prefix+".\uffff", r.BetweenOpts{Index: "users"})).Filter(r.Row.Field("protocol").Ne("internal"))
				if filter != "" {
					term = term.Filter(r.Row.Field("user").Match(filter))
				}
				term = term.Group(r.Row.Field("user").Match(fmt.Sprintf("^%s[.]([^.]*)(?:[.][^.]*)*$", prefix)).Field("groups").Nth(0).Field("str")).Count().Ungroup().Map(func(t r.Term) r.Term {
					return r.Branch(t.HasFields("group"), r.Object("prefix", r.Add(prefix+".", t.Field("group")), "count", t.Field("reduction")), r.Object("prefix", prefix, "count", t.Field("reduction")))
				})
			}
		} else {
			if prefix == "" {
				term = r.Table("sessions").Filter(r.Row.Field("protocol").Ne("internal"))
			} else {
				term = r.Table("sessions").GetAllByIndex("users", prefix).Union(r.Table("sessions").Between(prefix+".", prefix+".\uffff", r.BetweenOpts{Index: "users"})).Filter(r.Row.Field("protocol").Ne("internal"))
			}
			if filter != "" {
				term = term.Filter(r.Row.Field("user").Match(filter))
			}
			term = term.Count()
		}

		cur, err := term.Run(db)
		defer cur.Close()
		if err != nil {
			req.Error(ErrInternal, err.Error(), nil)
			return
		}
		var all []interface{}
		if err := cur.All(&all); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		if countSubprefixes {
			req.Result(all)
		} else if len(all) > 0 {
			req.Result(ei.M{"count": all[0]})
		} else {
			req.Result(ei.M{"count": 0})
		}

	case "sys.session.kick":
		fallthrough
	case "sys.session.reload":
		action := req.Method[12:]
		prefix := ei.N(req.Params).M("connid").StringZ()

		if len(prefix) < 16 {
			req.Error(ErrInvalidParams, "", nil)
			return
		}

		connuser, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff").
			Pluck("user").
			Run(db)
		defer connuser.Close()
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		var userd interface{}
		if err := connuser.One(&userd); err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		user := ei.N(userd).M("user").Lower().StringZ()
		tags := nc.getTags(user)
		if !(ei.N(tags).M("@sys.session."+action).BoolZ() || ei.N(tags).M("@admin").BoolZ()) {
			req.Error(ErrPermissionDenied, "", nil)
			return
		}

		Log.WithFields(logrus.Fields{
			"connid":  nc.connId,
			"action":  action,
			"session": prefix,
			"by":      user,
		}).Printf("Session %s", action)

		res, err := r.Table("sessions").
			Between(prefix, prefix+"\uffff").
			Update(ei.M{action: true}).
			RunWrite(db)
		if err != nil {
			req.Error(ErrInternal, "", nil)
			return
		}
		req.Result(ei.M{action + "ed": res.Replaced})

	default:
		req.Error(ErrMethodNotFound, "", nil)
	}
}
<|endoftext|>


<commit_before>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flow

import (
	"sync"
	"time"
)

// Workflow represents the entire life cycle of a single document.
//
// A workflow begins with the creation of a document, and drives its
// life cycle through a sequence of responses to user actions or other
// external events.
//
// The engine in `flow` is visible primarily through workflows,
// documents and their behaviour.
type Workflow struct {
	id   uint64        // globally-unique workflow instance ID
	defn *WfDefinition // definition of this flow

	mutex     sync.Mutex
	node      *Node   // current node in the workflow
	path      []*Node // flow so far, tracked in order
	completed bool
	err       error // reason for failure, if aborted
}

// newWorkflow creates and initialises a workflow instance using the
// given definition.
func newWorkflow(wd *WfDefinition) *Workflow {
	// WARNING: In a truly busy application, this manner of generating
	// IDs could lead to clashes.
	t := time.Now().UTC().UnixNano()
	return &Workflow{id: uint64(t), defn: wd, path: make([]*Node, 0, 2)}
}

// moveToNode adds the first node to the path of this workflow, as a
// completed step of processing.  It then marks the second as the
// current node in the workflow.
//
// If `n2` is `nil`, then the workflow is deemed to have completed.
func (wf *Workflow) moveToNode(n1, n2 *Node) bool {
	for _, el := range wf.path {
		if el.id == n1.id {
			return false
		}
	}

	wf.mutex.Lock()
	defer wf.mutex.Unlock()

	wf.path = append(wf.path, n1)
	wf.node = n2
	if n2 == nil {
		wf.completed = true
	}
	return true
}

// abort marks this workflow as aborted, and records the error
// message.
func (wf *Workflow) abort(err error) {
	if err == nil {
		return
	}

	wf.mutex.Lock()
	defer wf.mutex.Unlock()

	wf.completed = true
	wf.err = err
}

// complete marks this workflow as completed normally.  This method
// should be used only when a manual intervention halts this workflow.
func (wf *Workflow) complete() {
	wf.mutex.Lock()
	defer wf.mutex.Unlock()

	wf.node = nil
	wf.completed = true
}
<commit_msg>Remove `workflow.go` to allow workflows to be active, stateless entities<commit_after><|endoftext|>


<commit_before>package main

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"sync"
	"time"
)

type _escLocalFS struct{}

var _escLocal _escLocalFS

type _escStaticFS struct{}

var _escStatic _escStaticFS

type _escDirectory struct {
	fs   http.FileSystem
	name string
}

type _escFile struct {
	compressed string
	size       int64
	modtime    int64
	local      string
	isDir      bool

	once sync.Once
	data []byte
	name string
}

func (_escLocalFS) Open(name string) (http.File, error) {
	f, present := _escData[path.Clean(name)]
	if !present {
		return nil, os.ErrNotExist
	}
	return os.Open(f.local)
}

func (_escStaticFS) prepare(name string) (*_escFile, error) {
	f, present := _escData[path.Clean(name)]
	if !present {
		return nil, os.ErrNotExist
	}
	var err error
	f.once.Do(func() {
		f.name = path.Base(name)
		if f.size == 0 {
			return
		}
		var gr *gzip.Reader
		b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed))
		gr, err = gzip.NewReader(b64)
		if err != nil {
			return
		}
		f.data, err = ioutil.ReadAll(gr)
	})
	if err != nil {
		return nil, err
	}
	return f, nil
}

func (fs _escStaticFS) Open(name string) (http.File, error) {
	f, err := fs.prepare(name)
	if err != nil {
		return nil, err
	}
	return f.File()
}

func (dir _escDirectory) Open(name string) (http.File, error) {
	return dir.fs.Open(dir.name + name)
}

func (f *_escFile) File() (http.File, error) {
	type httpFile struct {
		*bytes.Reader
		*_escFile
	}
	return &httpFile{
		Reader:   bytes.NewReader(f.data),
		_escFile: f,
	}, nil
}

func (f *_escFile) Close() error {
	return nil
}

func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func (f *_escFile) Stat() (os.FileInfo, error) {
	return f, nil
}

func (f *_escFile) Name() string {
	return f.name
}

func (f *_escFile) Size() int64 {
	return f.size
}

func (f *_escFile) Mode() os.FileMode {
	return 0
}

func (f *_escFile) ModTime() time.Time {
	return time.Unix(f.modtime, 0)
}

func (f *_escFile) IsDir() bool {
	return f.isDir
}

func (f *_escFile) Sys() interface{} {
	return f
}

// FS returns a http.Filesystem for the embedded assets. If useLocal is true,
// the filesystem's contents are instead used.
func FS(useLocal bool) http.FileSystem {
	if useLocal {
		return _escLocal
	}
	return _escStatic
}

// Dir returns a http.Filesystem for the embedded assets on a given prefix dir.
// If useLocal is true, the filesystem's contents are instead used.
func Dir(useLocal bool, name string) http.FileSystem {
	if useLocal {
		return _escDirectory{fs: _escLocal, name: name}
	}
	return _escDirectory{fs: _escStatic, name: name}
}

// FSByte returns the named file from the embedded assets. If useLocal is
// true, the filesystem's contents are instead used.
func FSByte(useLocal bool, name string) ([]byte, error) {
	if useLocal {
		f, err := _escLocal.Open(name)
		if err != nil {
			return nil, err
		}
		return ioutil.ReadAll(f)
	}
	f, err := _escStatic.prepare(name)
	if err != nil {
		return nil, err
	}
	return f.data, nil
}

// FSMustByte is the same as FSByte, but panics if name is not present.
func FSMustByte(useLocal bool, name string) []byte {
	b, err := FSByte(useLocal, name)
	if err != nil {
		panic(err)
	}
	return b
}

// FSString is the string version of FSByte.
func FSString(useLocal bool, name string) (string, error) {
	b, err := FSByte(useLocal, name)
	return string(b), err
}

// FSMustString is the string version of FSMustByte.
func FSMustString(useLocal bool, name string) string {
	return string(FSMustByte(useLocal, name))
}

var _escData = map[string]*_escFile{

	"/templates/status.html": {
		local:   "templates/status.html",
		size:    3181,
		modtime: 1442049075,
		compressed: `
H4sIAAAJbogA/7RXTVPrNhRdJ79C4ym7IhNKZhrqeAMMXTQUmraLt1Osm9jzHClPUgi8TP77u5I/Yjsm
BL9hg+UjnSude0+uTBCbZRoGMTAeBiYxKYT3IG8fpmS7JfR/UDqRgux2gZ9N9oM0EV9JrGA+9nxfgOGC
0ZmURhvFVhEXNJJL32wSY0CdlxP+Jf2NDvxIa7/EznHlLBHA6TJBmtYeUZCOPW1eU9AxgPFO3c8BG2ai
uNgI1DoFJva7Hd3EvYX9nuH0uxQg2BJ+xbFNCyiyJXMpzPkGkkVsrslMpvwPsusHfk4LZpK/hv1+wJNn
EqVM67EXIYOhOOXZiXgQ3qdyxtLAx2F9pZIbu6ZXxfSKid8d2gsMm6VQTGQv7i8mV+HpgOevuCMHoYEj
r2d5yj1xwAt2IuaSZKK8/EBEG2Y0lpeXq8MBwVzVoeEhNGjBJpjyEsGBchJqZwmf1qASaGy53a5UIsyc
eGf0cu4Rmp2O5ovpP8zAwNnwg6RhF9KgE8uKr/Ay+e5p6/O5xfwz0UYuFFs28jo5WiGHjC7OGsDoAKBN
aMJe6sDU8Ft4fq/2uee+vWMB7hFSpriURlHMqXWpkOpVOZH1GJnRBenGG3XlHSW+lRP28vHdsmKRA7PW
3Rr42JHaOtPVT3WmwhAVKxcu/m9lkiXsD+XE0Aylt+x1alDYYn/s8if2dsjHlJm5VMtm0AJvCXaYgfKJ
zfsL3g86a+OdEuDOGpg4xH3ibOT67drAHhnmiK4sasGst8nT4zRHshrixf2Lkau/MWt4dV+PCf23eNvt
7LRiYgHoJaeEWMwmsNpW8jphMmVqCz4eFrPF7ejZHD7goMxf4aCgKMlBp2/15gSwppF+q9GfzBl24Ay6
kGr9pEX0nf14+ojyOy50F/VN3qliDvbrSmzNhHVfJNfCaGe9gvsXm0E6tZ8a1o032YKKTZ0LkZvMSzpC
vVZj1p0ZutC6+SsubF6L1rhH8xBX1ssuSq4mbxHulC0X+nYLgtt4xSBXnSbQlH3jsFN15wFOFZ4FP6K8
Gu+zpPfL0b5v7ttm9mGM3dL+l9H/EQAA//+wnVLJbQwAAA==
`,
	},

	"/": {
		isDir: true,
		local: "/",
	},

	"/templates": {
		isDir: true,
		local: "/templates",
	},
}
<commit_msg>Build templates.go with new esc<commit_after>package main

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"sync"
	"time"
)

type _escLocalFS struct{}

var _escLocal _escLocalFS

type _escStaticFS struct{}

var _escStatic _escStaticFS

type _escDirectory struct {
	fs   http.FileSystem
	name string
}

type _escFile struct {
	compressed string
	size       int64
	modtime    int64
	local      string
	isDir      bool

	once sync.Once
	data []byte
	name string
}

func (_escLocalFS) Open(name string) (http.File, error) {
	f, present := _escData[path.Clean(name)]
	if !present {
		return nil, os.ErrNotExist
	}
	return os.Open(f.local)
}

func (_escStaticFS) prepare(name string) (*_escFile, error) {
	f, present := _escData[path.Clean(name)]
	if !present {
		return nil, os.ErrNotExist
	}
	var err error
	f.once.Do(func() {
		f.name = path.Base(name)
		if f.size == 0 {
			return
		}
		var gr *gzip.Reader
		b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed))
		gr, err = gzip.NewReader(b64)
		if err != nil {
			return
		}
		f.data, err = ioutil.ReadAll(gr)
	})
	if err != nil {
		return nil, err
	}
	return f, nil
}

func (fs _escStaticFS) Open(name string) (http.File, error) {
	f, err := fs.prepare(name)
	if err != nil {
		return nil, err
	}
	return f.File()
}

func (dir _escDirectory) Open(name string) (http.File, error) {
	return dir.fs.Open(dir.name + name)
}

func (f *_escFile) File() (http.File, error) {
	type httpFile struct {
		*bytes.Reader
		*_escFile
	}
	return &httpFile{
		Reader:   bytes.NewReader(f.data),
		_escFile: f,
	}, nil
}

func (f *_escFile) Close() error {
	return nil
}

func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func (f *_escFile) Stat() (os.FileInfo, error) {
	return f, nil
}

func (f *_escFile) Name() string {
	return f.name
}

func (f *_escFile) Size() int64 {
	return f.size
}

func (f *_escFile) Mode() os.FileMode {
	return 0
}

func (f *_escFile) ModTime() time.Time {
	return time.Unix(f.modtime, 0)
}

func (f *_escFile) IsDir() bool {
	return f.isDir
}

func (f *_escFile) Sys() interface{} {
	return f
}

// FS returns a http.Filesystem for the embedded assets. If useLocal is true,
// the filesystem's contents are instead used.
func FS(useLocal bool) http.FileSystem {
	if useLocal {
		return _escLocal
	}
	return _escStatic
}

// Dir returns a http.Filesystem for the embedded assets on a given prefix dir.
// If useLocal is true, the filesystem's contents are instead used.
func Dir(useLocal bool, name string) http.FileSystem {
	if useLocal {
		return _escDirectory{fs: _escLocal, name: name}
	}
	return _escDirectory{fs: _escStatic, name: name}
}

// FSByte returns the named file from the embedded assets. If useLocal is
// true, the filesystem's contents are instead used.
func FSByte(useLocal bool, name string) ([]byte, error) {
	if useLocal {
		f, err := _escLocal.Open(name)
		if err != nil {
			return nil, err
		}
		b, err := ioutil.ReadAll(f)
		f.Close()
		return b, err
	}
	f, err := _escStatic.prepare(name)
	if err != nil {
		return nil, err
	}
	return f.data, nil
}

// FSMustByte is the same as FSByte, but panics if name is not present.
func FSMustByte(useLocal bool, name string) []byte {
	b, err := FSByte(useLocal, name)
	if err != nil {
		panic(err)
	}
	return b
}

// FSString is the string version of FSByte.
func FSString(useLocal bool, name string) (string, error) {
	b, err := FSByte(useLocal, name)
	return string(b), err
}

// FSMustString is the string version of FSMustByte.
func FSMustString(useLocal bool, name string) string {
	return string(FSMustByte(useLocal, name))
}

var _escData = map[string]*_escFile{

	"/templates/status.html": {
		local:   "templates/status.html",
		size:    3181,
		modtime: 1442049075,
		compressed: `
H4sIAAAJbogA/7RXTY/bNhA9W7+CEJpbl4rSGKhTWpdskB7qdFO3PfRGiWOLqES65HidreD/XpD6sCxr
Ha+KXCzpkW/IN/M0lFmOZZGwHLhIGEosIPkI+v7TmlQVoX+CsVIrcjyyqB4MWCHV3yQ3sFmGUaQAheI0
1RotGr7LhKKZLiM8SEQwd91A9Ib+QOMoszbqsLtMl6lUIGgpFc2sDYmBYhlafCrA5gAY3rqeBw4cs7xd
CMy+AK5Oq11dxD8lwQwF/VcrULyE71FQlxYwpCIbrfDuAHKb4zuS6kL8RI4BixoaS7V4SoKACflIsoJb
uwwzrZBLBSZ0A3mcfCx0ygsW5fFgptEHN2fWx+yOqx89OmPI0wLagfrB/96l2ggwIJrHTCsByoIIk2Dm
eMZfZwxFy5Zqo0ktKmw2RCxytCxC0c1OYlJKdQ7NL6F4BFsBPyEsclsY7iX5vAcjYbBkVe2MVLgh4Sv6
ZhMSWu+ONpPpbxwh9jZ8IWk+hRRPYjnxPV4t319dfb5tMX+WFvXW8HKQ19XVCnlk8frVAFhcAHQIrfiX
c2CN4h4ev1b7xnP/fMUCIiSkS3Enja6kurUuPdJ5VW5kPWS4eE2m8RZTeVeJz+WEf3n5anWxyIVZz93K
IiEfxzrT2//VmVpD9KzcuviPHcoSTpvyYmiN0nv+tEYj1fa07e4Vez7kQ8Fxo005DNriI8EuM9Bd8zj5
SyvnXNfGJyXA75VhnrAI8/rO99s9wgmZN4jtTRrBnLfJ54d1g9Q1rCryHerdrzt0R/e7JaG/t0/Hoxs2
XG2BEOqVEIe5BPbbSlMnQTJduIIv5+1oezqGLoefeAld/loHsbYkF51+1JsrQCMz+1yjv5kzn8CJp5DO
+smI6A/u4+klyj8IZaeoH/JuFXOx3lTiaCac+zK9V2i99VruLzyFYu0+NZwb39cTejb1LqwqIjcd/Xis
3+wLY547M/Gh7fAtbm1+Fm1wjjYh3jov+yiNmqZF+F2OHOhVBUq4eO1No7qQMJT93mO36m4C3Cq8Dn5F
eT/et5IedHenvnlqm/WHMYv8v4zgvwAAAP//sJ1SyW0MAAA=
`,
	},

	"/": {
		isDir: true,
		local: "/",
	},

	"/templates": {
		isDir: true,
		local: "/templates",
	},
}
<|endoftext|>


<commit_before>package xlsx

import (
	"fmt"
	"regexp"
	"text/template"
	"time"
)

// Templates for the various XML content in XLST files
var (
	TemplateContentTypes          *template.Template
	TemplateRelationships         *template.Template
	TemplateWorkbook              *template.Template
	TemplateWorkbookRelationships *template.Template
	TemplateStyles                *template.Template
	TemplateStringLookups         *template.Template
	TemplateSheetStart            *template.Template
	TemplateApp                   *template.Template
	TemplateCore                  *template.Template
)

// Template function for integer addition. This is useful to convert between
// zero-based and one-based array offsets within templates
func plus(i int, n int) string {
	return fmt.Sprintf("%d", i+n)
}

// Template function for time formatting
func timeFormat(t time.Time) string {
	return t.Format(time.RFC3339)
}

func init() {
	re := regexp.MustCompile("\n[\t\n\f\r ]*")
	funcMap := template.FuncMap{"plus": plus, "timeFormat": timeFormat}

	TemplateContentTypes = template.Must(template.New("templateContentTypes").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateContentTypes, "")))
	TemplateRelationships = template.Must(template.New("templateRelationships").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateRelationships, "")))
	TemplateWorkbook = template.Must(template.New("templateWorkbook").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateWorkbook, "")))
	TemplateWorkbookRelationships = template.Must(template.New("templateWorkbookRelationships").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateWorkbookRelationships, "")))
	TemplateStyles = template.Must(template.New("templateStyles").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateStyles, "")))
	TemplateStringLookups = template.Must(template.New("templateStringLookups").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateStringLookups, "")))
	TemplateSheetStart = template.Must(template.New("templateSheetStart").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateSheetStart, "")))
	TemplateApp = template.Must(template.New("templateApp").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateApp, "")))
	TemplateCore = template.Must(template.New("templateCore").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateCore, "")))
}

const templateContentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
      <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
      <Default Extension="xml" ContentType="application/xml"/>
      <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
      {{ range $i, $_ := . }}
      <Override PartName="/xl/worksheets/sheet{{plus $i 1}}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
      {{ end }}
      <Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
      <Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
      <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
      <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
  </Types>`

const templateRelationships = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
      <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
      <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
      <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
  </Relationships>`

const templateWorkbook = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
      <fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303"/>
      <workbookPr defaultThemeVersion="124226"/>
      <bookViews>
          <workbookView xWindow="480" yWindow="60" windowWidth="18195" windowHeight="8505"/>
      </bookViews>
      <sheets>
          {{ range $i, $e := . }}
          <sheet name="{{$e}}" sheetId="{{plus $i 1 }}" r:id="rId{{plus $i 1}}"/>
          {{ end }}
      </sheets>
      <calcPr calcId="145621"/>
  </workbook>`

const templateWorkbookRelationships = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
      {{ range $i, $_ := . }}
      <Relationship Id="rId{{plus $i 1}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet{{plus $i 1}}.xml"/>
      {{ end }}
      {{ $i := len . }}
      <Relationship Id="rId{{plus $i 1}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
      <Relationship Id="rId{{plus $i 2}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
  </Relationships>`

const templateStyles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  `

const templateStringLookups = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="{{len .}}" uniqueCount="{{len .}}">
{{range .}}<si><t>{{.}}</t></si>{{end}}
</sst>`

const templateSheetStart = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
            <sheetViews>
        <sheetView workbookViewId="0"/>
      </sheetViews>
      <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
        <cols>
          {{range $i, $e := .Cols}}
          <col min="{{plus $i 1}}" max="{{plus $i 1}}" width="{{$e.Width}}" customWidth="1" style="1"/>
          {{end}}
        </cols>
      <sheetData>`

const templateApp = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <Application>None</Application>
  <DocSecurity>0</DocSecurity>
  <ScaleCrop>false</ScaleCrop>
  <HeadingPairs>
    <vt:vector size="2" baseType="variant">
      <vt:variant>
        <vt:lpstr>Worksheets</vt:lpstr>
      </vt:variant>
      <vt:variant>
        <vt:i4>{{ len . }}</vt:i4>
      </vt:variant>
    </vt:vector>
  </HeadingPairs>
  <TitlesOfParts>
    <vt:vector size="1" baseType="lpstr">
      {{ range $i, $e := . }}
      <vt:lpstr>{{$e}}</vt:lpstr>
      {{ end }}
    </vt:vector>
  </TitlesOfParts>
  <LinksUpToDate>false</LinksUpToDate>
  <SharedDoc>false</SharedDoc>
  <HyperlinksChanged>false</HyperlinksChanged>
</Properties>`

const templateCore = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <dc:creator>{{.CreatedBy}}</dc:creator>
    <cp:lastModifiedBy>{{.ModifiedBy}}</cp:lastModifiedBy>
    <dcterms:created xsi:type="dcterms:W3CDTF">{{timeFormat .CreatedAt}}</dcterms:created>
    <dcterms:modified xsi:type="dcterms:W3CDTF">{{timeFormat .ModifiedAt}}</dcterms:modified>
  </cp:coreProperties>`
<commit_msg>Change ordering in template<commit_after>package xlsx

import (
	"fmt"
	"regexp"
	"text/template"
	"time"
)

// Templates for the various XML content in XLST files
var (
	TemplateContentTypes          *template.Template
	TemplateRelationships         *template.Template
	TemplateWorkbook              *template.Template
	TemplateWorkbookRelationships *template.Template
	TemplateStyles                *template.Template
	TemplateStringLookups         *template.Template
	TemplateSheetStart            *template.Template
	TemplateApp                   *template.Template
	TemplateCore                  *template.Template
)

// Template function for integer addition. This is useful to convert between
// zero-based and one-based array offsets within templates
func plus(i int, n int) string {
	return fmt.Sprintf("%d", i+n)
}

// Template function for time formatting
func timeFormat(t time.Time) string {
	return t.Format(time.RFC3339)
}

func init() {
	re := regexp.MustCompile("\n[\t\n\f\r ]*")
	funcMap := template.FuncMap{"plus": plus, "timeFormat": timeFormat}

	TemplateContentTypes = template.Must(template.New("templateContentTypes").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateContentTypes, "")))
	TemplateRelationships = template.Must(template.New("templateRelationships").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateRelationships, "")))
	TemplateWorkbook = template.Must(template.New("templateWorkbook").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateWorkbook, "")))
	TemplateWorkbookRelationships = template.Must(template.New("templateWorkbookRelationships").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateWorkbookRelationships, "")))
	TemplateStyles = template.Must(template.New("templateStyles").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateStyles, "")))
	TemplateStringLookups = template.Must(template.New("templateStringLookups").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateStringLookups, "")))
	TemplateSheetStart = template.Must(template.New("templateSheetStart").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateSheetStart, "")))
	TemplateApp = template.Must(template.New("templateApp").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateApp, "")))
	TemplateCore = template.Must(template.New("templateCore").Funcs(funcMap).Parse(re.ReplaceAllLiteralString(templateCore, "")))
}

const templateContentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
      <Default Extension="xml" ContentType="application/xml"/>
      <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
      <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
      {{ range $i, $_ := . }}
      <Override PartName="/xl/worksheets/sheet{{plus $i 1}}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
      {{ end }}
      <Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
      <Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
      <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
      <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
  </Types>`

const templateRelationships = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
      <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
      <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
      <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
  </Relationships>`

const templateWorkbook = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
      <fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303"/>
      <workbookPr defaultThemeVersion="124226"/>
      <bookViews>
          <workbookView xWindow="480" yWindow="60" windowWidth="18195" windowHeight="8505"/>
      </bookViews>
      <sheets>
          {{ range $i, $e := . }}
          <sheet name="{{$e}}" sheetId="{{plus $i 1 }}" r:id="rId{{plus $i 1}}"/>
          {{ end }}
      </sheets>
      <calcPr calcId="145621"/>
  </workbook>`

const templateWorkbookRelationships = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
      {{ range $i, $_ := . }}
      <Relationship Id="rId{{plus $i 1}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet{{plus $i 1}}.xml"/>
      {{ end }}
      {{ $i := len . }}
      <Relationship Id="rId{{plus $i 1}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
      <Relationship Id="rId{{plus $i 2}}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
  </Relationships>`

const templateStyles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  `

const templateStringLookups = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="{{len .}}" uniqueCount="{{len .}}">
{{range .}}<si><t>{{.}}</t></si>{{end}}
</sst>`

const templateSheetStart = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
            <sheetViews>
        <sheetView workbookViewId="0"/>
      </sheetViews>
      <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
        <cols>
          {{range $i, $e := .Cols}}
          <col min="{{plus $i 1}}" max="{{plus $i 1}}" width="{{$e.Width}}" customWidth="1" style="1"/>
          {{end}}
        </cols>
      <sheetData>`

const templateApp = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <Application>None</Application>
  <DocSecurity>0</DocSecurity>
  <ScaleCrop>false</ScaleCrop>
  <HeadingPairs>
    <vt:vector size="2" baseType="variant">
      <vt:variant>
        <vt:lpstr>Worksheets</vt:lpstr>
      </vt:variant>
      <vt:variant>
        <vt:i4>{{ len . }}</vt:i4>
      </vt:variant>
    </vt:vector>
  </HeadingPairs>
  <TitlesOfParts>
    <vt:vector size="1" baseType="lpstr">
      {{ range $i, $e := . }}
      <vt:lpstr>{{$e}}</vt:lpstr>
      {{ end }}
    </vt:vector>
  </TitlesOfParts>
  <LinksUpToDate>false</LinksUpToDate>
  <SharedDoc>false</SharedDoc>
  <HyperlinksChanged>false</HyperlinksChanged>
</Properties>`

const templateCore = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <dc:creator>{{.CreatedBy}}</dc:creator>
    <cp:lastModifiedBy>{{.ModifiedBy}}</cp:lastModifiedBy>
    <dcterms:created xsi:type="dcterms:W3CDTF">{{timeFormat .CreatedAt}}</dcterms:created>
    <dcterms:modified xsi:type="dcterms:W3CDTF">{{timeFormat .ModifiedAt}}</dcterms:modified>
  </cp:coreProperties>`
<|endoftext|>


<commit_before>package postmark

import (
	"net/url"
	"path"
	"strconv"

	"golang.org/x/net/context"
)

// Templates defines the functionality of the template resource
type Templates interface {
	// Get retrieves an individual template
	// http://developer.postmarkapp.com/developer-api-templates.html#get-template
	Get(ctx context.Context, id int64) (*Template, error)

	// Create creates a new template within Postmark
	// http://developer.postmarkapp.com/developer-api-templates.html#create-template
	Create(ctx context.Context, tmpl *Template) (*TemplateResp, error)

	// Edit modifies an existing template
	// http://developer.postmarkapp.com/developer-api-templates.html#edit-template
	Edit(ctx context.Context, id int64, tmpl *Template) (*TemplateResp, error)

	// List returns a list of all existing templates
	// http://developer.postmarkapp.com/developer-api-templates.html#template-list
	List(ctx context.Context, count, offset int) (*TemplateList, error)

	// Delete permanently deletes a template from Postmark
	// http://developer.postmarkapp.com/developer-api-templates.html#delete-template
	Delete(ctx context.Context, id int64) (*TemplateResp, error)

	// Validate allows a template's validity to be checked without sending the template
	// http://developer.postmarkapp.com/developer-api-templates.html#validate-template
	Validate(ctx context.Context, tmpl *TemplateValidation) (*TemplateValidationResp, error)

	// Email sends an email with the given template. This is a wrapper around the `EmailWithTemplate`
	// method that lives on the `Emails` resource, but lives here in order to match the Postmark docs.
	// http://developer.postmarkapp.com/developer-api-templates.html#email-with-template
	Email(ctx context.Context, email *EmailWithTemplate) (*EmailResponse, error)
}

type templates struct {
	pm *postmark
}

var _ Templates = (*templates)(nil)

// Template defines the template entities within postmark
type Template struct {
	TemplateID         int64 `json:"TemplateId"`
	Name               string
	Subject            string
	HTMLBody           string `json:"HtmlBody"`
	TextBody           string
	AssociatedServerID int64 `json:"AssociatedServerId"`
	Active             bool
}

func (t *templates) Get(ctx context.Context, id int64) (*Template, error) {
	tmpl := new(Template)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "GET",
		Path:   path.Join("templates", i64toa(id)),
		Target: tmpl,
	})
	if err != nil {
		return nil, err
	}
	return tmpl, nil
}

// TemplateResp defines the response after template manipulation
type TemplateResp struct {
	TemplateID int64 `json:"TemplateId"`
	Name       string
	Active     bool

	ErrorCode int
	Message   string
}

func (t *templates) Create(ctx context.Context, tmpl *Template) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "POST",
		Path:    "templates",
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

func (t *templates) Edit(ctx context.Context, id int64, tmpl *Template) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "PUT",
		Path:    path.Join("templates", i64toa(id)),
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

// TemplateList defines a list of template entities
type TemplateList struct {
	TemplateCount int64
	Templates     []*Template
}

func (t *templates) List(ctx context.Context, count, offset int) (*TemplateList, error) {
	tmplList := new(TemplateList)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "GET",
		Path:   "templates",
		Params: url.Values{
			"count":  {strconv.Itoa(count)},
			"offset": {strconv.Itoa(offset)},
		},
		Target: tmplList,
	})
	if err != nil {
		return nil, err
	}
	return tmplList, nil
}

func (t *templates) Delete(ctx context.Context, id int64) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "DELETE",
		Path:   path.Join("templates", i64toa(id)),
		Target: tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

// TemplateValidation defines the structure of a template sent for validation with the API
type TemplateValidation struct {
	Subject                    string
	HTMLBody                   string `json:"HtmlBody"`
	TextBody                   string
	TestRenderModel            map[string]interface{}
	InlineCSSForHTMLTestRender bool `json:"InlineCssForHtmlTestRender"`
}

// TemplateValidationResp defines the result of a template validation call
type TemplateValidationResp struct {
	AllContentIsValid      bool
	ContentIsValid         bool
	ValidationErrors       []TemplateValidationErr
	RenderedContent        string
	SuggestedTemplateModel map[string]interface{}
}

// TemplateValidationErr defines an error that occured while validating a template
type TemplateValidationErr struct {
	Message           string
	Line              int
	CharacterPosition int
}

func (t *templates) Validate(ctx context.Context, tmpl *TemplateValidation) (*TemplateValidationResp, error) {
	tmplResp := new(TemplateValidationResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "POST",
		Path:    path.Join("templates", "validate"),
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

func (t *templates) Email(ctx context.Context, email *EmailWithTemplate) (*EmailResponse, error) {
	return t.pm.Emails().EmailWithTemplate(ctx, email)
}

// helpers

// cleans up syntax for putting ids into URLs
func i64toa(i int64) string {
	return strconv.FormatInt(i, 10)
}
<commit_msg>fix template validate response body format<commit_after>package postmark

import (
	"net/url"
	"path"
	"strconv"

	"golang.org/x/net/context"
)

// Templates defines the functionality of the template resource
type Templates interface {
	// Get retrieves an individual template
	// http://developer.postmarkapp.com/developer-api-templates.html#get-template
	Get(ctx context.Context, id int64) (*Template, error)

	// Create creates a new template within Postmark
	// http://developer.postmarkapp.com/developer-api-templates.html#create-template
	Create(ctx context.Context, tmpl *Template) (*TemplateResp, error)

	// Edit modifies an existing template
	// http://developer.postmarkapp.com/developer-api-templates.html#edit-template
	Edit(ctx context.Context, id int64, tmpl *Template) (*TemplateResp, error)

	// List returns a list of all existing templates
	// http://developer.postmarkapp.com/developer-api-templates.html#template-list
	List(ctx context.Context, count, offset int) (*TemplateList, error)

	// Delete permanently deletes a template from Postmark
	// http://developer.postmarkapp.com/developer-api-templates.html#delete-template
	Delete(ctx context.Context, id int64) (*TemplateResp, error)

	// Validate allows a template's validity to be checked without sending the template
	// http://developer.postmarkapp.com/developer-api-templates.html#validate-template
	Validate(ctx context.Context, tmpl *TemplateValidation) (*TemplateValidationResp, error)

	// Email sends an email with the given template. This is a wrapper around the `EmailWithTemplate`
	// method that lives on the `Emails` resource, but lives here in order to match the Postmark docs.
	// http://developer.postmarkapp.com/developer-api-templates.html#email-with-template
	Email(ctx context.Context, email *EmailWithTemplate) (*EmailResponse, error)
}

type templates struct {
	pm *postmark
}

var _ Templates = (*templates)(nil)

// Template defines the template entities within postmark
type Template struct {
	TemplateID         int64 `json:"TemplateId"`
	Name               string
	Subject            string
	HTMLBody           string `json:"HtmlBody"`
	TextBody           string
	AssociatedServerID int64 `json:"AssociatedServerId"`
	Active             bool
}

func (t *templates) Get(ctx context.Context, id int64) (*Template, error) {
	tmpl := new(Template)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "GET",
		Path:   path.Join("templates", i64toa(id)),
		Target: tmpl,
	})
	if err != nil {
		return nil, err
	}
	return tmpl, nil
}

// TemplateResp defines the response after template manipulation
type TemplateResp struct {
	TemplateID int64 `json:"TemplateId"`
	Name       string
	Active     bool

	ErrorCode int
	Message   string
}

func (t *templates) Create(ctx context.Context, tmpl *Template) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "POST",
		Path:    "templates",
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

func (t *templates) Edit(ctx context.Context, id int64, tmpl *Template) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "PUT",
		Path:    path.Join("templates", i64toa(id)),
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

// TemplateList defines a list of template entities
type TemplateList struct {
	TemplateCount int64
	Templates     []*Template
}

func (t *templates) List(ctx context.Context, count, offset int) (*TemplateList, error) {
	tmplList := new(TemplateList)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "GET",
		Path:   "templates",
		Params: url.Values{
			"count":  {strconv.Itoa(count)},
			"offset": {strconv.Itoa(offset)},
		},
		Target: tmplList,
	})
	if err != nil {
		return nil, err
	}
	return tmplList, nil
}

func (t *templates) Delete(ctx context.Context, id int64) (*TemplateResp, error) {
	tmplResp := new(TemplateResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method: "DELETE",
		Path:   path.Join("templates", i64toa(id)),
		Target: tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

// TemplateValidation defines the structure of a template sent for validation with the API
type TemplateValidation struct {
	Subject                    string
	HTMLBody                   string `json:"HtmlBody"`
	TextBody                   string
	TestRenderModel            map[string]interface{}
	InlineCSSForHTMLTestRender bool `json:"InlineCssForHtmlTestRender"`
}

// TemplateValidationResp defines the result of a template validation call
type TemplateValidationResp struct {
	AllContentIsValid      bool
	HTMLBody               TemplateValidationResult `json:"HtmlBody"`
	TextBody               TemplateValidationResult
	Subject                TemplateValidationResult
	SuggestedTemplateModel map[string]interface{}
}

// TemplateValidationResult contains information describing the result of a validation for
// a particular type of template.
type TemplateValidationResult struct {
	ContentIsValid   bool
	ValidationErrors []TemplateValidationErr
	RenderedContent  string
}

// TemplateValidationErr defines an error that occured while validating a template
type TemplateValidationErr struct {
	Message           string
	Line              int
	CharacterPosition int
}

func (t *templates) Validate(ctx context.Context, tmpl *TemplateValidation) (*TemplateValidationResp, error) {
	tmplResp := new(TemplateValidationResp)
	_, err := t.pm.Exec(ctx, &Request{
		Method:  "POST",
		Path:    path.Join("templates", "validate"),
		Payload: tmpl,
		Target:  tmplResp,
	})
	if err != nil {
		return nil, err
	}
	return tmplResp, nil
}

func (t *templates) Email(ctx context.Context, email *EmailWithTemplate) (*EmailResponse, error) {
	return t.pm.Emails().EmailWithTemplate(ctx, email)
}

// helpers

// cleans up syntax for putting ids into URLs
func i64toa(i int64) string {
	return strconv.FormatInt(i, 10)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	log "github.com/sirupsen/logrus"
	"html/template"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"strings"

	"github.com/xyproto/mime"
	"github.com/xyproto/permissions2"
)

const (
	pathsep = string(os.PathSeparator)
)

var (
	mimereader *mime.Reader
)

// When serving a file. The file must exist. Must be given a full filename.
func filePage(w http.ResponseWriter, req *http.Request, filename string, perm *permissions.Permissions, luapool *lStatePool) {

	// Mimetypes
	ext := path.Ext(filename)

	// Markdown pages are handled differently
	if ext == ".md" {

		w.Header().Add("Content-Type", "text/html")
		b, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the markdown page
		markdownPage(w, b, filename)

		return

	} else if ext == ".amber" {

		w.Header().Add("Content-Type", "text/html")
		amberdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}
		// Try reading data.lua as well, if possible
		luafilename := path.Join(path.Dir(filename), "data.lua")
		luadata, err := read(luafilename)
		if err != nil {
			// Could not find and/or read data.lua
			luadata = []byte{}
		}
		// Make functions from the given Lua data available
		funcs := make(template.FuncMap)
		if len(luadata) > 0 {
			// There was Lua code available. Now make the functions and
			// variables available for the template.
			funcs, err = luaFunctionMap(w, req, luadata, luafilename, perm, luapool)
			if err != nil {
				if debugMode {
					// Use the Lua filename as the title
					prettyError(w, luafilename, luadata, err.Error(), "lua")
				} else {
					log.Error(err)
				}
				return
			}
			if debugMode && verboseMode {
				s := "The following functions from " + luafilename + "\n"
				s += "are made available for use in " + filename + ":\n\t"
				// Create a comma separated list of the available functions
				for key := range funcs {
					s += key + ", "
				}
				// Remove the final comma
				if strings.HasSuffix(s, ", ") {
					s = s[:len(s)-2]
				}
				// Output the message
				log.Info(s)
			}
		}

		// Render the Amber page, using functions from data.lua, if available
		amberPage(w, filename, luafilename, amberdata, funcs)

		return

	} else if ext == ".gcss" {

		w.Header().Add("Content-Type", "text/css")
		gcssdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the GCSS page as CSS
		gcssPage(w, filename, gcssdata)

		return

	} else if ext == ".jsx" {

		w.Header().Add("Content-Type", "text/javascript")
		jsxdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the JSX page as JavaScript
		jsxPage(w, filename, jsxdata)

		return

	} else if ext == ".lua" {

		// If in debug mode, let the Lua script print to a buffer first, in
		// case there are errors that should be displayed instead.

		// If debug mode is enabled
		if debugMode {
			// Use a buffered ResponseWriter for delaying the output
			recorder := httptest.NewRecorder()
			// The flush function writes the ResponseRecorder to the ResponseWriter
			flushFunc := func() {
				writeRecorder(w, recorder)
				Flush(w)
			}
			// Run the lua script, without the possibility to flush
			if err := runLua(recorder, req, filename, perm, luapool, flushFunc); err != nil {
				errortext := err.Error()
				filedata, err := read(filename)
				if err != nil {
					// Use the error as the file contents when displaying the error message
					// if reading the file failed.
					filedata = []byte(err.Error())
				}
				// If there were errors, display an error page
				prettyError(w, filename, filedata, errortext, "lua")
			} else {
				// If things went well, write to the ResponseWriter
				writeRecorder(w, recorder)
			}
		} else {
			// The flush function just flushes the ResponseWriter
			flushFunc := func() {
				Flush(w)
			}
			// Run the lua script, with the flush feature
			if err := runLua(w, req, filename, perm, luapool, flushFunc); err != nil {
				// Output the non-fatal error message to the log
				log.Error("Error in ", filename+":", err)
			}
		}

		return

	}

	// Set the correct Content-Type
	mimereader.SetHeader(w, ext)
	// Write to the ResponseWriter, from the File
	file, err := os.Open(filename)
	defer file.Close()
	if err != nil {
		if debugMode {
			fmt.Fprintf(w, "Can't open %s: %s", filename, err)
		} else {
			log.Errorf("Can't open %s: %s", filename, err)
		}
	}
	// Serve the file
	io.Copy(w, file)
	return
}

// Directory listing
func directoryListing(w http.ResponseWriter, rootdir, dirname string) {
	var buf bytes.Buffer
	for _, filename := range getFilenames(dirname) {

		// Find the full name
		fullFilename := dirname

		// Add a "/" after the directory name, if missing
		if !strings.HasSuffix(fullFilename, pathsep) {
			fullFilename += pathsep
		}

		// Add the filename at the end
		fullFilename += filename

		// Remove the root directory from the link path
		urlpath := fullFilename[len(rootdir)+1:]

		// Output different entries for files and directories
		buf.WriteString(easyLink(filename, urlpath, isDir(fullFilename)))
	}
	title := dirname
	// Strip the leading "./"
	if strings.HasPrefix(title, "."+pathsep) {
		title = title[1+len(pathsep):]
	}
	// Strip double "/" at the end, just keep one
	// Replace "//" with just "/"
	if strings.Contains(title, pathsep+pathsep) {
		title = strings.Replace(title, pathsep+pathsep, pathsep, everyInstance)
	}

	// Use the application title for the main page
	//if title == "" {
	//	title = versionString
	//}

	var htmldata []byte
	if buf.Len() > 0 {
		htmldata = []byte(easyPage(title, buf.String()))
	} else {
		htmldata = []byte(easyPage(title, "Empty directory"))
	}

	// If the auto-refresh feature has been enabled
	if autoRefresh {
		// Insert JavaScript for refreshing the page into the generated HTML
		htmldata = insertAutoRefresh(htmldata)
	}

	w.Write(htmldata)
}

// When serving a directory.
// The directory must exist. Must be given a full filename.
func dirPage(w http.ResponseWriter, req *http.Request, rootdir, dirname string, perm *permissions.Permissions, luapool *lStatePool) {
	// If the URL does not end with a slash, redirect to an URL that does
	if !strings.HasSuffix(req.URL.Path, "/") {
		http.Redirect(w, req, req.URL.Path+"/", http.StatusMovedPermanently)
		return
	}
	// Handle the serving of index files, if needed
	for _, indexfile := range indexFilenames {
		filename := path.Join(dirname, indexfile)
		if exists(filename) {
			filePage(w, req, filename, perm, luapool)
			return
		}
	}
	// Serve a directory listing of no index file is found
	directoryListing(w, rootdir, dirname)
}

// When a file is not found
func noPage(filename string) string {
	return easyPage("Not found", "File not found: "+filename)
}

// Serve all files in the current directory, or only a few select filetypes (html, css, js, png and txt)
func registerHandlers(mux *http.ServeMux, servedir string, perm *permissions.Permissions, luapool *lStatePool) {
	// Read in the mimetype information from the system. Set UTF-8 when setting Content-Type.
	mimereader = mime.New("/etc/mime.types", true)
	rootdir := servedir

	// Handle all requests with this function
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		if perm.Rejected(w, req) {
			// Get and call the Permission Denied function
			perm.DenyFunction()(w, req)
			// Reject the request by returning
			return
		}

		// TODO: HTTP Basic Auth check goes here, see "scoreserver"

		urlpath := req.URL.Path
		filename := url2filename(servedir, urlpath)
		// Remove the trailing slash from the filename, if any
		noslash := filename
		if strings.HasSuffix(filename, pathsep) {
			noslash = filename[:len(filename)-1]
		}
		hasdir := exists(filename) && isDir(filename)
		hasfile := exists(noslash)

		// TODO: Only set the server header if configured to do so

		// Set the server header.
		w.Header().Set("Server", "Algernon")

		// Share the directory or file
		if hasdir {
			dirPage(w, req, rootdir, filename, perm, luapool)
			return
		} else if !hasdir && hasfile {
			// Share a single file instead of a directory
			filePage(w, req, noslash, perm, luapool)
			return
		}

		// Not found
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, noPage(filename))
	})
}
<commit_msg>Using the version string in the server header<commit_after>package main

import (
	"bytes"
	"fmt"
	log "github.com/sirupsen/logrus"
	"html/template"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"strings"

	"github.com/xyproto/mime"
	"github.com/xyproto/permissions2"
)

const (
	pathsep = string(os.PathSeparator)
)

var (
	mimereader *mime.Reader
)

// When serving a file. The file must exist. Must be given a full filename.
func filePage(w http.ResponseWriter, req *http.Request, filename string, perm *permissions.Permissions, luapool *lStatePool) {

	// Mimetypes
	ext := path.Ext(filename)

	// Markdown pages are handled differently
	if ext == ".md" {

		w.Header().Add("Content-Type", "text/html")
		b, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the markdown page
		markdownPage(w, b, filename)

		return

	} else if ext == ".amber" {

		w.Header().Add("Content-Type", "text/html")
		amberdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}
		// Try reading data.lua as well, if possible
		luafilename := path.Join(path.Dir(filename), "data.lua")
		luadata, err := read(luafilename)
		if err != nil {
			// Could not find and/or read data.lua
			luadata = []byte{}
		}
		// Make functions from the given Lua data available
		funcs := make(template.FuncMap)
		if len(luadata) > 0 {
			// There was Lua code available. Now make the functions and
			// variables available for the template.
			funcs, err = luaFunctionMap(w, req, luadata, luafilename, perm, luapool)
			if err != nil {
				if debugMode {
					// Use the Lua filename as the title
					prettyError(w, luafilename, luadata, err.Error(), "lua")
				} else {
					log.Error(err)
				}
				return
			}
			if debugMode && verboseMode {
				s := "The following functions from " + luafilename + "\n"
				s += "are made available for use in " + filename + ":\n\t"
				// Create a comma separated list of the available functions
				for key := range funcs {
					s += key + ", "
				}
				// Remove the final comma
				if strings.HasSuffix(s, ", ") {
					s = s[:len(s)-2]
				}
				// Output the message
				log.Info(s)
			}
		}

		// Render the Amber page, using functions from data.lua, if available
		amberPage(w, filename, luafilename, amberdata, funcs)

		return

	} else if ext == ".gcss" {

		w.Header().Add("Content-Type", "text/css")
		gcssdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the GCSS page as CSS
		gcssPage(w, filename, gcssdata)

		return

	} else if ext == ".jsx" {

		w.Header().Add("Content-Type", "text/javascript")
		jsxdata, err := read(filename)
		if err != nil {
			if debugMode {
				fmt.Fprintf(w, "Unable to read %s: %s", filename, err)
			} else {
				log.Errorf("Unable to read %s: %s", filename, err)
			}
			return
		}

		// Render the JSX page as JavaScript
		jsxPage(w, filename, jsxdata)

		return

	} else if ext == ".lua" {

		// If in debug mode, let the Lua script print to a buffer first, in
		// case there are errors that should be displayed instead.

		// If debug mode is enabled
		if debugMode {
			// Use a buffered ResponseWriter for delaying the output
			recorder := httptest.NewRecorder()
			// The flush function writes the ResponseRecorder to the ResponseWriter
			flushFunc := func() {
				writeRecorder(w, recorder)
				Flush(w)
			}
			// Run the lua script, without the possibility to flush
			if err := runLua(recorder, req, filename, perm, luapool, flushFunc); err != nil {
				errortext := err.Error()
				filedata, err := read(filename)
				if err != nil {
					// Use the error as the file contents when displaying the error message
					// if reading the file failed.
					filedata = []byte(err.Error())
				}
				// If there were errors, display an error page
				prettyError(w, filename, filedata, errortext, "lua")
			} else {
				// If things went well, write to the ResponseWriter
				writeRecorder(w, recorder)
			}
		} else {
			// The flush function just flushes the ResponseWriter
			flushFunc := func() {
				Flush(w)
			}
			// Run the lua script, with the flush feature
			if err := runLua(w, req, filename, perm, luapool, flushFunc); err != nil {
				// Output the non-fatal error message to the log
				log.Error("Error in ", filename+":", err)
			}
		}

		return

	}

	// Set the correct Content-Type
	mimereader.SetHeader(w, ext)
	// Write to the ResponseWriter, from the File
	file, err := os.Open(filename)
	defer file.Close()
	if err != nil {
		if debugMode {
			fmt.Fprintf(w, "Can't open %s: %s", filename, err)
		} else {
			log.Errorf("Can't open %s: %s", filename, err)
		}
	}
	// Serve the file
	io.Copy(w, file)
	return
}

// Directory listing
func directoryListing(w http.ResponseWriter, rootdir, dirname string) {
	var buf bytes.Buffer
	for _, filename := range getFilenames(dirname) {

		// Find the full name
		fullFilename := dirname

		// Add a "/" after the directory name, if missing
		if !strings.HasSuffix(fullFilename, pathsep) {
			fullFilename += pathsep
		}

		// Add the filename at the end
		fullFilename += filename

		// Remove the root directory from the link path
		urlpath := fullFilename[len(rootdir)+1:]

		// Output different entries for files and directories
		buf.WriteString(easyLink(filename, urlpath, isDir(fullFilename)))
	}
	title := dirname
	// Strip the leading "./"
	if strings.HasPrefix(title, "."+pathsep) {
		title = title[1+len(pathsep):]
	}
	// Strip double "/" at the end, just keep one
	// Replace "//" with just "/"
	if strings.Contains(title, pathsep+pathsep) {
		title = strings.Replace(title, pathsep+pathsep, pathsep, everyInstance)
	}

	// Use the application title for the main page
	//if title == "" {
	//	title = versionString
	//}

	var htmldata []byte
	if buf.Len() > 0 {
		htmldata = []byte(easyPage(title, buf.String()))
	} else {
		htmldata = []byte(easyPage(title, "Empty directory"))
	}

	// If the auto-refresh feature has been enabled
	if autoRefresh {
		// Insert JavaScript for refreshing the page into the generated HTML
		htmldata = insertAutoRefresh(htmldata)
	}

	w.Write(htmldata)
}

// When serving a directory.
// The directory must exist. Must be given a full filename.
func dirPage(w http.ResponseWriter, req *http.Request, rootdir, dirname string, perm *permissions.Permissions, luapool *lStatePool) {
	// If the URL does not end with a slash, redirect to an URL that does
	if !strings.HasSuffix(req.URL.Path, "/") {
		http.Redirect(w, req, req.URL.Path+"/", http.StatusMovedPermanently)
		return
	}
	// Handle the serving of index files, if needed
	for _, indexfile := range indexFilenames {
		filename := path.Join(dirname, indexfile)
		if exists(filename) {
			filePage(w, req, filename, perm, luapool)
			return
		}
	}
	// Serve a directory listing of no index file is found
	directoryListing(w, rootdir, dirname)
}

// When a file is not found
func noPage(filename string) string {
	return easyPage("Not found", "File not found: "+filename)
}

// Serve all files in the current directory, or only a few select filetypes (html, css, js, png and txt)
func registerHandlers(mux *http.ServeMux, servedir string, perm *permissions.Permissions, luapool *lStatePool) {
	// Read in the mimetype information from the system. Set UTF-8 when setting Content-Type.
	mimereader = mime.New("/etc/mime.types", true)
	rootdir := servedir

	// Handle all requests with this function
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		if perm.Rejected(w, req) {
			// Get and call the Permission Denied function
			perm.DenyFunction()(w, req)
			// Reject the request by returning
			return
		}

		// TODO: HTTP Basic Auth check goes here, see "scoreserver"

		urlpath := req.URL.Path
		filename := url2filename(servedir, urlpath)
		// Remove the trailing slash from the filename, if any
		noslash := filename
		if strings.HasSuffix(filename, pathsep) {
			noslash = filename[:len(filename)-1]
		}
		hasdir := exists(filename) && isDir(filename)
		hasfile := exists(noslash)

		// Set the server header.
		w.Header().Set("Server", versionString)

		// Share the directory or file
		if hasdir {
			dirPage(w, req, rootdir, filename, perm, luapool)
			return
		} else if !hasdir && hasfile {
			// Share a single file instead of a directory
			filePage(w, req, noslash, perm, luapool)
			return
		}

		// Not found
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, noPage(filename))
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

func Index(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Welcome!")
}

func PostIndex(w http.ResponseWriter, r *http.Request) {
	var (
		posts   Posts
		id      int
		title   string
		content string
		posted  string
	)

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p := Post{id, title, content, posted}
		posts = append(posts, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(posts); err != nil {
		log.Fatal(err)
	}
}

func PostShow(w http.ResponseWriter, r *http.Request) {
	var (
		p       Post
		id      int
		title   string
		content string
		posted  string
	)

	vars := mux.Vars(r)
	postId := vars["postId"]

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts WHERE ID = ?", postId)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(p); err != nil {
		log.Fatal(err)
	}
}

func PostCreate(w http.ResponseWriter, r *http.Request) {
	var post Post

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}
	log.Print(post)
}
<commit_msg>Add functionality to create a post<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

func Index(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Welcome!")
}

func PostIndex(w http.ResponseWriter, r *http.Request) {
	var (
		posts   Posts
		id      int
		title   string
		content string
		posted  string
	)

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p := Post{id, title, content, posted}
		posts = append(posts, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(posts); err != nil {
		log.Fatal(err)
	}
}

func PostShow(w http.ResponseWriter, r *http.Request) {
	var (
		p       Post
		id      int
		title   string
		content string
		posted  string
	)

	vars := mux.Vars(r)
	postId := vars["postId"]

	db := dbConnection()
	rows, err := db.Query("SELECT * FROM posts WHERE ID = ?", postId)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		p = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(p); err != nil {
		log.Fatal(err)
	}
}

func PostCreate(w http.ResponseWriter, r *http.Request) {
	var (
		post    Post
		id      int
		title   string
		content string
		posted  string
	)

	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		log.Fatal(err)
	}
	if err := r.Body.Close(); err != nil {
		log.Fatal(err)
	}

	if err := json.Unmarshal(body, &post); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422)
	}

	db := dbConnection()
	_, err = db.Query("INSERT INTO posts (title, content) values (?, ?)", post.Title, post.Content)
	if err != nil {
		log.Fatal(err)
	}

	rows, err := db.Query("SELECT * FROM posts ORDER BY id DESC LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &title, &content, &posted)
		if err != nil {
			log.Fatal(err)
		}
		post = Post{id, title, content, posted}
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	JSONHandler(w, r)
	if err := json.NewEncoder(w).Encode(post); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

// BaseTemplateContent is HTML for base.tmpl
const BaseTemplateContent = `<html>
  <head>
  </head>
  <body>
  </body>
</html>
`
<commit_msg>modify base template<commit_after>package main

// BaseTemplateContent is HTML for base.tmpl
const BaseTemplateContent = `<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
  </head>
  <body>
  </body>
</html>
`
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/kennygrant/sanitize"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

func healthHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "All systems go.")
}

func notFoundHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "404 Not Found.", 404)
}

func putHandler(w http.ResponseWriter, r *http.Request) {
	if config.ALLOWPUT == "true" {
		vars := mux.Vars(r)
		filename := sanitize.Path(filepath.Base(vars["filename"]))
		contentLength := r.ContentLength
		var reader io.Reader
		var err error
		reader = r.Body
		if contentLength == -1 {
			// queue file to disk, because s3 needs content length
			var f io.Reader
			f = reader
			var b bytes.Buffer
			n, err := io.CopyN(&b, f, _24K+1)
			if err != nil && err != io.EOF {
				log.Printf("%s", err.Error())
				http.Error(w, "Internal server error.", 500)
				return
			}
			if n > _24K {
				file, err := ioutil.TempFile(config.Temp, "transfer-")
				if err != nil {
					log.Printf("%s", err.Error())
					http.Error(w, "Internal server error.", 500)
					return
				}
				defer file.Close()
				n, err = io.Copy(file, io.MultiReader(&b, f))
				if err != nil {
					os.Remove(file.Name())
					log.Printf("%s", err.Error())
					http.Error(w, "Internal server error.", 500)
					return
				}
				reader, err = os.Open(file.Name())
			} else {
				reader = bytes.NewReader(b.Bytes())
			}
			contentLength = n
		}
		token := Encode(10000000 + int64(rand.Intn(1000000000)))
		log.Printf("Uploading %s %s %d", token, filename, contentLength)
		if err = storage.Put(token, filename, reader, uint64(contentLength)); err != nil {
			log.Printf("%s", err.Error())
			http.Error(w, errors.New("Could not save file").Error(), 500)
			return
		}
		w.Header().Set("Content-Type", "text/plain")
		var hash string
		if hash, err = storage.HardLinkSha512(token, filename); err != nil {
			log.Printf("%s", err.Error())
		} else if err == nil {
			log.Printf("Hashed %s %s as %s", token, filename, hash)
			fmt.Fprintf(w, "{\"sha512\":\"%s\",\"filename\":\"%s\"}", hash, filename)
		}
	} else {
		http.Error(w, "403 Forbidden. Uploading is disabled.", 403)
	}
}

func getHandler(w http.ResponseWriter, r *http.Request) {
	var filename string
	var reader io.ReadSeeker
	var modTime time.Time
	var err error
	gouseragent := regexp.MustCompile("Go.*package http")
	if config.ALLOWGET == "true" {
		vars := mux.Vars(r)
		hash := vars["hash"]
		filename, reader, _, modTime, err = storage.Seeker(hash)
		if err != nil {
			if strings.Index(err.Error(), "no such file or directory") >= 0 {
				log.Printf("%s", err.Error())
				// try from peer
				var found = false
				if !gouseragent.MatchString(r.UserAgent()) {
					// dtfc specific
					found, filename, reader, _, modTime, err = getFromPeers(hash)
					if err != nil {
						http.Error(w, "Internal server error.", 500)
						return
					}
				}
				// end try from peer
				if found == false {
					notFoundHandler(w, r)
					return
				}
			} else {
				log.Printf("%s", err.Error())
				http.Error(w, "Could not retrieve file.", 500)
				return
			}
		}
		w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
		http.ServeContent(w, r, filename, modTime, reader)
		// refresh peers a percentage of the time
		if rand.Intn(10) == 0 {
			refreshPeerList()
		}
	} else {
		http.Error(w, "403 Forbidden. Downloading is disabled.", 403)
	}
}

func RedirectHandler(h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/health.html" {
		} else if ipAddrFromRemoteAddr(r.Host) == "127.0.0.1" {
		} else if ipAddrFromRemoteAddr(r.Host) == "::1" {
		} else if r.Header.Get("X-Forwarded-Proto") != "https" && r.Method == "GET" {
			http.Redirect(w, r, "https://"+r.Host+r.RequestURI, 301)
			return
		}
		h.ServeHTTP(w, r)
	}
}
<commit_msg>simplify the puthandler<commit_after>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/kennygrant/sanitize"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

func healthHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "All systems go.")
}

func notFoundHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "404 Not Found.", 404)
}

func putHandler(w http.ResponseWriter, r *http.Request) {
	if config.ALLOWPUT == "true" {
		vars := mux.Vars(r)
		filename := sanitize.Path(filepath.Base(vars["filename"]))
		var err error
		file, err := ioutil.TempFile(config.Temp, "transfer-")
		if err != nil {
			log.Printf("%s", err.Error())
			http.Error(w, "Internal server error.", 500)
			return
		} else {
			defer file.Close()
			_, err = io.Copy(file, r.Body)
			if err != nil {
				os.Remove(file.Name())
				log.Printf("%s", err.Error())
				http.Error(w, "Internal server error.", 500)
				return
			} else {
				w.Header().Set("Content-Type", "text/plain")
				var hash string
				if hash, err = storage.HardLinkSha512Path(file.Name(), filename); err != nil {
					log.Printf("%s", err.Error())
				} else if err == nil {
					log.Printf("Hashed %s as %s", filename, hash)
					fmt.Fprintf(w, "{\"sha512\":\"%s\",\"filename\":\"%s\"}", hash, filename)
				}
			}
		}
	} else {
		http.Error(w, "403 Forbidden. Uploading is disabled.", 403)
	}
}

func getHandler(w http.ResponseWriter, r *http.Request) {
	var filename string
	var reader io.ReadSeeker
	var modTime time.Time
	var err error
	gouseragent := regexp.MustCompile("Go.*package http")
	if config.ALLOWGET == "true" {
		vars := mux.Vars(r)
		hash := vars["hash"]
		filename, reader, _, modTime, err = storage.Seeker(hash)
		if err != nil {
			if strings.Index(err.Error(), "no such file or directory") >= 0 {
				log.Printf("%s", err.Error())
				// try from peer
				var found = false
				if !gouseragent.MatchString(r.UserAgent()) {
					// dtfc specific
					found, filename, reader, _, modTime, err = getFromPeers(hash)
					if err != nil {
						http.Error(w, "Internal server error.", 500)
						return
					}
				}
				// end try from peer
				if found == false {
					notFoundHandler(w, r)
					return
				}
			} else {
				log.Printf("%s", err.Error())
				http.Error(w, "Could not retrieve file.", 500)
				return
			}
		}
		w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
		http.ServeContent(w, r, filename, modTime, reader)
		// refresh peers a percentage of the time
		if rand.Intn(10) == 0 {
			refreshPeerList()
		}
	} else {
		http.Error(w, "403 Forbidden. Downloading is disabled.", 403)
	}
}

func RedirectHandler(h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/health.html" {
		} else if ipAddrFromRemoteAddr(r.Host) == "127.0.0.1" {
		} else if ipAddrFromRemoteAddr(r.Host) == "::1" {
		} else if r.Header.Get("X-Forwarded-Proto") != "https" && r.Method == "GET" {
			http.Redirect(w, r, "https://"+r.Host+r.RequestURI, 301)
			return
		}
		h.ServeHTTP(w, r)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func Auth(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO Handle auth.
		// Only continue if user is authorized
		fn(w, r)
	}
}

// AddFile handles a Post Request for a Sia file and saves it to the DB
func (sf *Sunfish) AddFile(w http.ResponseWriter, r *http.Request) {
	var siafile Siafile
	const maxSiaFilesize = 1 << 20 // 1 MiB
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, maxSiaFilesize))

	if err != nil {
		sf.logger.Panicln("ERROR: Could not ready body of request.")
	}

	if err := r.Body.Close(); err != nil {
		sf.logger.Panicln("ERROR: Could not close body of request.")
	}

	if err := json.Unmarshal(body, &siafile); err != nil {
		// If cannot process the Siafile
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			sf.logger.Panicln("ERROR: Could not encode json response.")
		}
		sf.logger.Println("INFO: Could not process the uploaded Siafile.")
		return
	}

	// Validate fields
	var errors []string
	// Filename has to contain '.sia'
	if !strings.Contains(siafile.Filename, ".sia") || len(siafile.Filename) == 0 {
		errors = append(errors, "Bad Siafile upload")
	}
	if len(siafile.Title) == 0 {
		errors = append(errors, "Title field can not be blank")
	}
	for i, tag := range siafile.Tags {
		siafile.Tags[i] = strings.ToLower(tag)
	}

	if len(errors) > 0 {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(errors); err != nil {
			sf.logger.Panicln("ERROR: Siafile was not valid.")
		}
		return
	}

	// Handle saving the Siafile to the db and file system
	siafile.UploadedTime = time.Now()
	err = sf.DB.C("siafiles").Insert(siafile)

	if err != nil {
		sf.logger.Panicln("ERROR: Could not save record into database.")
	}
	sf.logger.Println("INFO: Uploaded new Siafile")

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(siafile); err != nil {
		sf.logger.Panicln("ERROR: Could not encode siafile")
	}
}

//  GetAll returns all siafiles as a json list.
func (sf *Sunfish) GetAll(w http.ResponseWriter, r *http.Request) {
	// TODO Pagination and sorts
	var siafiles []Siafile

	// Select removes the content from query results use for not returning .sia
	err := sf.DB.C("siafiles").Find(bson.M{}).All(&siafiles)
	if err != nil {
		sf.logger.Panicln("ERROR: Couldnot find all siafiles.")
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafiles); err != nil {
		sf.logger.Println(err)
	}
}

// GetFile takes the hash of a Siafile in the URL and returns the Siafile in JSON
func (sf *Sunfish) GetFile(w http.ResponseWriter, r *http.Request) {
	var id string
	var siafile Siafile

	vars := mux.Vars(r)
	id = vars["id"]

	// Query and find by one id
	err := sf.DB.C("siafiles").FindId(bson.ObjectIdHex(id)).One(&siafile)
	if err != nil {
		sf.logger.Panicln("ERROR: Could not find Siafile: ", bson.ObjectIdHex(id))
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafile); err != nil {
		sf.logger.Panicln("ERROR: Could not JSON encode Siafile:", siafile)
	}
}

// SearchFile takes a query parameter of tags and searches the DB for siafiles
// that match that tag.
func (sf *Sunfish) SearchFile(w http.ResponseWriter, r *http.Request) {
	var siafiles []Siafile
	var search string

	query := r.URL.Query()
	search = query.Get("tags")
	// Searches db or all siafiles that have the query string in it's tags
	err := sf.DB.C("siafiles").Find(bson.M{"tags": search}).All(&siafiles)

	if err != nil {
		sf.logger.Panicln("ERROR: searching Siafiles for tags: ", search)
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafiles); err != nil {
		sf.logger.Panicln("ERROR: Could not encode Siafile", siafiles)
	}
}

// Takes the hash of a Siafile in the URL and removes it from DB
func (sf *Sunfish) DeleteFile(w http.ResponseWriter, r *http.Request) {
	var id string
	//var siafile Siafile

	vars := mux.Vars(r)
	id = vars["id"]

	// Db.C("siafiles").remove({'hash': hash})

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(id); err != nil {
		sf.logger.Println(err)
	}
}
<commit_msg>Switched to println and return<commit_after>package main

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func Auth(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO Handle auth.
		// Only continue if user is authorized
		fn(w, r)
	}
}

// AddFile handles a Post Request for a Sia file and saves it to the DB
func (sf *Sunfish) AddFile(w http.ResponseWriter, r *http.Request) {
	var siafile Siafile
	const maxSiaFilesize = 1 << 20 // 1 MiB
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, maxSiaFilesize))

	if err != nil {
		sf.logger.Println("ERROR: Could not ready body of request.")
		return
	}

	if err := r.Body.Close(); err != nil {
		sf.logger.Println("ERROR: Could not close body of request.")
		return
	}

	if err := json.Unmarshal(body, &siafile); err != nil {
		// If cannot process the Siafile
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			sf.logger.Println("ERROR: Could not encode json response.")
			return
		}
		sf.logger.Println("INFO: Could not process the uploaded Siafile.")
		return
	}

	// Validate fields
	var errors []string
	// Filename has to contain '.sia'
	if !strings.Contains(siafile.Filename, ".sia") || len(siafile.Filename) == 0 {
		errors = append(errors, "Bad Siafile upload")
	}
	if len(siafile.Title) == 0 {
		errors = append(errors, "Title field can not be blank")
	}
	for i, tag := range siafile.Tags {
		siafile.Tags[i] = strings.ToLower(tag)
	}

	if len(errors) > 0 {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(errors); err != nil {
			sf.logger.Println("ERROR: Siafile was not valid.")
			return
		}
		return
	}

	// Handle saving the Siafile to the db and file system
	siafile.UploadedTime = time.Now()
	err = sf.DB.C("siafiles").Insert(siafile)

	if err != nil {
		sf.logger.Println("ERROR: Could not save record into database.")
		return
	}
	sf.logger.Println("INFO: Uploaded new Siafile")

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(siafile); err != nil {
		sf.logger.Println("ERROR: Could not encode siafile")
		return
	}
}

//  GetAll returns all siafiles as a json list.
func (sf *Sunfish) GetAll(w http.ResponseWriter, r *http.Request) {
	// TODO Pagination and sorts
	var siafiles []Siafile

	// Select removes the content from query results use for not returning .sia
	err := sf.DB.C("siafiles").Find(bson.M{}).All(&siafiles)
	if err != nil {
		sf.logger.Println("ERROR: Couldnot find all siafiles.")
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafiles); err != nil {
		sf.logger.Println(err)
	}
}

// GetFile takes the hash of a Siafile in the URL and returns the Siafile in JSON
func (sf *Sunfish) GetFile(w http.ResponseWriter, r *http.Request) {
	var id string
	var siafile Siafile

	vars := mux.Vars(r)
	id = vars["id"]

	// Query and find by one id
	err := sf.DB.C("siafiles").FindId(bson.ObjectIdHex(id)).One(&siafile)
	if err != nil {
		sf.logger.Println("ERROR: Could not find Siafile: ", bson.ObjectIdHex(id))
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafile); err != nil {
		sf.logger.Println("ERROR: Could not JSON encode Siafile:", siafile)
		return
	}
}

// SearchFile takes a query parameter of tags and searches the DB for siafiles
// that match that tag.
func (sf *Sunfish) SearchFile(w http.ResponseWriter, r *http.Request) {
	var siafiles []Siafile
	var search string

	query := r.URL.Query()
	search = query.Get("tags")
	// Searches db or all siafiles that have the query string in it's tags
	err := sf.DB.C("siafiles").Find(bson.M{"tags": search}).All(&siafiles)

	if err != nil {
		sf.logger.Println("ERROR: searching Siafiles for tags: ", search)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(siafiles); err != nil {
		sf.logger.Println("ERROR: Could not encode Siafile", siafiles)
		return
	}
}

// Takes the hash of a Siafile in the URL and removes it from DB
func (sf *Sunfish) DeleteFile(w http.ResponseWriter, r *http.Request) {
	var id string
	//var siafile Siafile

	vars := mux.Vars(r)
	id = vars["id"]

	// Db.C("siafiles").remove({'hash': hash})

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(id); err != nil {
		sf.logger.Println(err)
	}
}
<|endoftext|>