<commit_before>package drax

import (
	"io"
	"net"

	"github.com/Sirupsen/logrus"
	"github.com/cpuguy83/drax/api"
	"github.com/cpuguy83/drax/api/errors"
	"github.com/cpuguy83/drax/rpc"
	"github.com/docker/distribution/registry/api/errcode"
	libkvstore "github.com/docker/libkv/store"
)

// nodeRPC handles communcations for node-level actions(e.g., addNode, removeNode)
type nodeRPC struct {
	*rpc.StreamLayer
	r *Raft
}

// clientRPC handles communications with k/v store clients
type clientRPC struct {
	*rpc.StreamLayer
	s *store
}

func (r *nodeRPC) addNode(req *rpc.Request) error {
	return r.r.AddPeer(req.Args[0])
}

func (r *nodeRPC) removeNode(req *rpc.Request) error {
	return r.r.RemovePeer(req.Args[0])
}

func (r *nodeRPC) handleConns() {
	for {
		conn, err := r.Accept()
		if err != nil {
			if err == rpc.ErrClosedConn {
				return
			}
			continue
		}

		go r.handleConn(conn)
	}
}

func (r *nodeRPC) handleConn(conn net.Conn) {
	defer conn.Close()
	var req rpc.Request
	if err := api.Decode(&req, conn); err != nil {
		logrus.Errorf("error handling K/V RPC connection: %v", err)
		return
	}

	logrus.Debugf("Got: %s(%s)", req.Method, req.Args)

	var h rpcHandlerFunc

	switch req.Method {
	case addNode:
		h = r.addNode
	case removeNode:
		h = r.removeNode
	}

	if !r.r.IsLeader() {
		r.ProxyRequest(r.r.GetLeader(), &req, conn)
		return
	}

	var res rpc.Response
	if err := h(&req); err != nil {
		res.Err = err.Error()
	}
	api.Encode(&res, conn)
}

func (r *clientRPC) Get(conn io.Writer, req *clientRequest) {
	var res api.Response
	kv, err := r.s.Get(req.Key)
	if err != nil {
		setError(&res, err)
		api.Encode(&res, conn)
		return
	}
	res.KV = libkvToKV(kv)
	api.Encode(&res, conn)
}

func (r *clientRPC) Put(conn io.Writer, req *clientRequest) {
	var res api.Response
	err := r.s.Put(req.Key, req.Value, &libkvstore.WriteOptions{TTL: req.TTL})
	if err != nil {
		setError(&res, err)
	}
	api.Encode(res, conn)
}

func waitClose(conn io.Reader, chStop chan struct{}) {
	buf := make([]byte, 1)
	for {
		_, err := conn.Read(buf)
		if err == io.EOF {
			close(chStop)
		}
		continue
	}
}

func (r *clientRPC) Watch(conn io.Writer, req *clientRequest) {
	chStop := make(chan struct{})
	go waitClose(req.body, chStop)
	chKv, err := r.s.Watch(req.Key, chStop)
	if err != nil {
		return
	}
	for kv := range chKv {
		api.Encode(libkvToKV(kv), conn)
	}
}

func (r *clientRPC) WatchTree(conn io.Writer, req *clientRequest) {
	chStop := make(chan struct{})
	go waitClose(req.body, chStop)
	chKv, err := r.s.WatchTree(req.Key, chStop)
	if err != nil {
		return
	}
	var apiKVList []*api.KVPair
	for kvList := range chKv {
		for _, kv := range kvList {
			apiKVList = append(apiKVList, libkvToKV(kv))
		}
		api.Encode(apiKVList, conn)
		apiKVList = nil
	}
}

func (r *clientRPC) List(conn io.Writer, req *clientRequest) {
	var res api.Response
	ls, err := r.s.List(req.Key)
	if err != nil {
		setError(&res, err)
	}

	var apiLs []*api.KVPair
	for _, kv := range ls {
		apiLs = append(apiLs, libkvToKV(kv))
	}
	res.List = apiLs
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) DeleteTree(conn io.Writer, req *clientRequest) {
	var res api.Response
	if err := r.s.DeleteTree(req.Key); err != nil {
		setError(&res, err)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) Delete(conn io.Writer, req *clientRequest) {
	var res api.Response
	if err := r.s.Delete(req.Key); err != nil {
		setError(&res, err)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) Exists(conn io.Writer, req *clientRequest) {
	var res api.Response
	exists, err := r.s.Exists(req.Key)
	if err != nil {
		setError(&res, err)
	}
	res.Exists = exists
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) AtomicPut(conn io.Writer, req *clientRequest) {
	var res api.Response
	ok, kv, err := r.s.AtomicPut(req.Key, req.Value, kvToLibKV(req.Previous), &libkvstore.WriteOptions{TTL: req.TTL})
	if err != nil {
		setError(&res, err)
	} else {
		res.Completed = ok
		res.KV = libkvToKV(kv)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) AtomicDelete(conn io.Writer, req *clientRequest) {
	var res api.Response
	ok, err := r.s.AtomicDelete(req.Key, kvToLibKV(req.Previous))
	if err != nil {
		setError(&res, err)
	}
	res.Completed = ok
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) handleConns() {
	for {
		conn, err := r.Accept()
		if err != nil {
			if err == rpc.ErrClosedConn {
				return
			}
			continue
		}
		go r.handleConn(conn)
	}
}

type clientRPCHandlerFn func(io.Writer, *clientRequest)
type clientRequest struct {
	*api.Request
	body io.Reader
}

func (r *clientRPC) handleConn(conn net.Conn) {
	defer conn.Close()
	var req api.Request
	if err := api.Decode(&req, conn); err != nil {
		logrus.Errorf("error handling K/V RPC connection: %v", err)
		return
	}

	logrus.Debugf("Got: %s(%s)", req.Action, req.Key)

	var h clientRPCHandlerFn

	switch req.Action {
	case api.Get:
		h = r.Get
	case api.Put:
		h = r.Put
	case api.Watch:
		h = r.Watch
	case api.WatchTree:
		h = r.WatchTree
	case api.List:
		h = r.List
	case api.DeleteTree:
		h = r.DeleteTree
	case api.AtomicPut:
		h = r.AtomicPut
	case api.AtomicDelete:
		h = r.AtomicDelete
	}

	h(conn, &clientRequest{&req, conn})
}

func libkvToKV(kv *libkvstore.KVPair) *api.KVPair {
	return &api.KVPair{
		Key:       kv.Key,
		Value:     kv.Value,
		LastIndex: kv.LastIndex,
	}
}

func kvToLibKV(kv *api.KVPair) *libkvstore.KVPair {
	return &libkvstore.KVPair{
		Key:       kv.Key,
		Value:     kv.Value,
		LastIndex: kv.LastIndex,
	}
}

func setError(res *api.Response, err error) {
	if err == nil {
		return
	}
	switch err {
	case ErrKeyNotFound:
		e := errors.StoreKeyNotFound.WithMessage(err.Error())
		res.Err = &e
	case ErrKeyModified:
		e := errors.StoreKeyModified.WithMessage(err.Error())
		res.Err = &e
	case ErrCallNotSupported:
		e := errcode.ErrorCodeUnsupported.WithMessage(err.Error())
		res.Err = &e
	default:
		e := errcode.ErrorCodeUnknown.WithMessage(err.Error())
		res.Err = &e
	}
}
<commit_msg>Add missing delete call from Client RPC handler<commit_after>package drax

import (
	"io"
	"net"

	"github.com/Sirupsen/logrus"
	"github.com/cpuguy83/drax/api"
	"github.com/cpuguy83/drax/api/errors"
	"github.com/cpuguy83/drax/rpc"
	"github.com/docker/distribution/registry/api/errcode"
	libkvstore "github.com/docker/libkv/store"
)

// nodeRPC handles communcations for node-level actions(e.g., addNode, removeNode)
type nodeRPC struct {
	*rpc.StreamLayer
	r *Raft
}

// clientRPC handles communications with k/v store clients
type clientRPC struct {
	*rpc.StreamLayer
	s *store
}

func (r *nodeRPC) addNode(req *rpc.Request) error {
	return r.r.AddPeer(req.Args[0])
}

func (r *nodeRPC) removeNode(req *rpc.Request) error {
	return r.r.RemovePeer(req.Args[0])
}

func (r *nodeRPC) handleConns() {
	for {
		conn, err := r.Accept()
		if err != nil {
			if err == rpc.ErrClosedConn {
				return
			}
			continue
		}

		go r.handleConn(conn)
	}
}

func (r *nodeRPC) handleConn(conn net.Conn) {
	defer conn.Close()
	var req rpc.Request
	if err := api.Decode(&req, conn); err != nil {
		logrus.Errorf("error handling K/V RPC connection: %v", err)
		return
	}

	logrus.Debugf("Got: %s(%s)", req.Method, req.Args)

	var h rpcHandlerFunc

	switch req.Method {
	case addNode:
		h = r.addNode
	case removeNode:
		h = r.removeNode
	}

	if !r.r.IsLeader() {
		r.ProxyRequest(r.r.GetLeader(), &req, conn)
		return
	}

	var res rpc.Response
	if err := h(&req); err != nil {
		res.Err = err.Error()
	}
	api.Encode(&res, conn)
}

func (r *clientRPC) Get(conn io.Writer, req *clientRequest) {
	var res api.Response
	kv, err := r.s.Get(req.Key)
	if err != nil {
		setError(&res, err)
		api.Encode(&res, conn)
		return
	}
	res.KV = libkvToKV(kv)
	api.Encode(&res, conn)
}

func (r *clientRPC) Put(conn io.Writer, req *clientRequest) {
	var res api.Response
	err := r.s.Put(req.Key, req.Value, &libkvstore.WriteOptions{TTL: req.TTL})
	if err != nil {
		setError(&res, err)
	}
	api.Encode(res, conn)
}

func waitClose(conn io.Reader, chStop chan struct{}) {
	buf := make([]byte, 1)
	for {
		_, err := conn.Read(buf)
		if err == io.EOF {
			close(chStop)
		}
		continue
	}
}

func (r *clientRPC) Watch(conn io.Writer, req *clientRequest) {
	chStop := make(chan struct{})
	go waitClose(req.body, chStop)
	chKv, err := r.s.Watch(req.Key, chStop)
	if err != nil {
		return
	}
	for kv := range chKv {
		api.Encode(libkvToKV(kv), conn)
	}
}

func (r *clientRPC) WatchTree(conn io.Writer, req *clientRequest) {
	chStop := make(chan struct{})
	go waitClose(req.body, chStop)
	chKv, err := r.s.WatchTree(req.Key, chStop)
	if err != nil {
		return
	}
	var apiKVList []*api.KVPair
	for kvList := range chKv {
		for _, kv := range kvList {
			apiKVList = append(apiKVList, libkvToKV(kv))
		}
		api.Encode(apiKVList, conn)
		apiKVList = nil
	}
}

func (r *clientRPC) List(conn io.Writer, req *clientRequest) {
	var res api.Response
	ls, err := r.s.List(req.Key)
	if err != nil {
		setError(&res, err)
	}

	var apiLs []*api.KVPair
	for _, kv := range ls {
		apiLs = append(apiLs, libkvToKV(kv))
	}
	res.List = apiLs
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) DeleteTree(conn io.Writer, req *clientRequest) {
	var res api.Response
	if err := r.s.DeleteTree(req.Key); err != nil {
		setError(&res, err)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) Delete(conn io.Writer, req *clientRequest) {
	var res api.Response
	if err := r.s.Delete(req.Key); err != nil {
		setError(&res, err)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) Exists(conn io.Writer, req *clientRequest) {
	var res api.Response
	exists, err := r.s.Exists(req.Key)
	if err != nil {
		setError(&res, err)
	}
	res.Exists = exists
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) AtomicPut(conn io.Writer, req *clientRequest) {
	var res api.Response
	ok, kv, err := r.s.AtomicPut(req.Key, req.Value, kvToLibKV(req.Previous), &libkvstore.WriteOptions{TTL: req.TTL})
	if err != nil {
		setError(&res, err)
	} else {
		res.Completed = ok
		res.KV = libkvToKV(kv)
	}
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) AtomicDelete(conn io.Writer, req *clientRequest) {
	var res api.Response
	ok, err := r.s.AtomicDelete(req.Key, kvToLibKV(req.Previous))
	if err != nil {
		setError(&res, err)
	}
	res.Completed = ok
	api.NewEncoder(conn).Encode(&res)
}

func (r *clientRPC) handleConns() {
	for {
		conn, err := r.Accept()
		if err != nil {
			if err == rpc.ErrClosedConn {
				return
			}
			continue
		}
		go r.handleConn(conn)
	}
}

type clientRPCHandlerFn func(io.Writer, *clientRequest)
type clientRequest struct {
	*api.Request
	body io.Reader
}

func (r *clientRPC) handleConn(conn net.Conn) {
	defer conn.Close()
	var req api.Request
	if err := api.Decode(&req, conn); err != nil {
		logrus.Errorf("error handling K/V RPC connection: %v", err)
		return
	}

	logrus.Debugf("Got: %s(%s)", req.Action, req.Key)

	var h clientRPCHandlerFn

	switch req.Action {
	case api.Get:
		h = r.Get
	case api.Put:
		h = r.Put
	case api.Watch:
		h = r.Watch
	case api.WatchTree:
		h = r.WatchTree
	case api.List:
		h = r.List
	case api.Delete:
		h = r.Delete
	case api.DeleteTree:
		h = r.DeleteTree
	case api.AtomicPut:
		h = r.AtomicPut
	case api.AtomicDelete:
		h = r.AtomicDelete
	}

	h(conn, &clientRequest{&req, conn})
}

func libkvToKV(kv *libkvstore.KVPair) *api.KVPair {
	return &api.KVPair{
		Key:       kv.Key,
		Value:     kv.Value,
		LastIndex: kv.LastIndex,
	}
}

func kvToLibKV(kv *api.KVPair) *libkvstore.KVPair {
	return &libkvstore.KVPair{
		Key:       kv.Key,
		Value:     kv.Value,
		LastIndex: kv.LastIndex,
	}
}

func setError(res *api.Response, err error) {
	if err == nil {
		return
	}
	switch err {
	case ErrKeyNotFound:
		e := errors.StoreKeyNotFound.WithMessage(err.Error())
		res.Err = &e
	case ErrKeyModified:
		e := errors.StoreKeyModified.WithMessage(err.Error())
		res.Err = &e
	case ErrCallNotSupported:
		e := errcode.ErrorCodeUnsupported.WithMessage(err.Error())
		res.Err = &e
	default:
		e := errcode.ErrorCodeUnknown.WithMessage(err.Error())
		res.Err = &e
	}
}
<|endoftext|>


<commit_before>/*
	Go library for simple i-doit api usage

	Copyright (C) 2017 Carsten Seeger

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

	@author Carsten Seeger
	@copyright Copyright (C) 2017 Carsten Seeger
	@license http://www.gnu.org/licenses/gpl-3.0 GNU General Public License 3
	@link https://github.com/cseeger-epages/i-doit-go-api
*/

package goidoit

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

// request id
var id int = 0

// basic api interface
type ApiMethods interface {
	Request() (Response, error)
	Search() (SearchResponse, error)
	GetObjectByID() (Response, error)
	/*
		Login()
		Logout()
		IsLoggedIn()
	*/
}

// api struct used for implementing the apiMethods interface
type Api struct {
	url, apikey string
}

// i-doit api request structure
// as defined in https://kb.i-doit.com/pages/viewpage.action?pageId=7831613
// also there is a list of methods available
type Request struct {
	Version string      `json:"version"`
	Method  string      `json:"method"`
	Params  interface{} `json:"params"`
	Id      int         `json:"id"`
}

// i-doit api response structure
type Response struct {
	Jsonrpc string      `json:"jsonrpc"`
	Result  interface{} `json:"result"`
	Error   IdoitError  `json:"error"`
}

// i-doit api response structure used for search requests
//
// the map is used to handle type assertions
type SearchResponse struct {
	Jsonrpc string
	Result  []map[string]interface{}
	Error   IdoitError
}

// i-doit api error structure
type IdoitError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

// Apikey used for requests
type Apikey struct {
	Apikey string `json:"apikey"`
}

// api constructor
func Newapi(url string, apikey string) (*Api, error) {
	if len(url) != 0 && len(apikey) != 0 {
		a := Api{url, apikey}
		return &a, nil
	}
	return nil, errors.New("url or apikey empty")
}

// Request i-doit Api using method an parameter
// parameter should be implemented as a struct
// be sure to use uppercase first letter for your struct
// entrys to make it public
func (a Api) Request(method string, parameters interface{}) (Response, error) {

	var params = GetParams(a, parameters)
	id = getID()

	data := Request{
		Version: "2.0",
		Method:  method,
		Params:  params,
		Id:      id,
	}

	dataJson, err := json.Marshal(data)

	// logging tbd
	//fmt.Println("Request: ", string(dataJson))

	req, err := http.NewRequest("POST", a.url, bytes.NewBuffer(dataJson))
	if err != nil {
		fmt.Println("REQUEST ERROR: ", err)
		return Response{}, err
	}
	req.Header.Add("content-type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("REQUEST ERROR: ", err)
		return Response{}, err
	}
	var ret = ParseResponse(resp)
	return ret, nil
}

// search CMDB using a string
//
// The search function does handle type assertions
// for simple output usage
func (a *Api) Search(query string) (SearchResponse, error) {
	params := struct {
		Query string `json:"q"`
	}{query}
	data, err := a.Request("idoit.search", &params)
	if err != nil {
		return SearchResponse{}, err
	}

	// do type assertions for easy output handling
	ret := SearchResponse{Jsonrpc: data.Jsonrpc, Error: data.Error}

	ret.Error.Data = ""
	if data.Error.Data != nil {
		ret.Error.Data = data.Error.Data.(string)
	}

	results := data.Result.([]interface{})
	for i := range results {
		ret.Result = append(ret.Result, results[i].(map[string]interface{}))
	}
	return ret, nil
}

// increment request id's
func getID() int {
	id++
	return id
}

// append nessesary parameters to user provided one
func GetParams(a Api, parameters interface{}) interface{} {

	var params map[string]string
	apikey := Apikey{a.apikey}

	jsonParameters, err := json.Marshal(parameters)

	if err != nil {
		log.Fatal("JSON ERROR: ", err)
	}

	json.Unmarshal(jsonParameters, &params)
	jsonApikey, err := json.Marshal(apikey)

	if err != nil {
		log.Fatal("JSON ERROR: ", err)
	}

	json.Unmarshal(jsonApikey, &params)

	return params
}

// parse json response
func ParseResponse(resp *http.Response) Response {
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal("PARSING ERROR: ", err)
	}

	// logging tbd
	//fmt.Println("Response: ", string(data))

	var ret Response
	_ = json.Unmarshal(data, &ret)

	return ret
}
<commit_msg>change comments for interface methods<commit_after>/*
	Go library for simple i-doit api usage

	Copyright (C) 2017 Carsten Seeger

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

	@author Carsten Seeger
	@copyright Copyright (C) 2017 Carsten Seeger
	@license http://www.gnu.org/licenses/gpl-3.0 GNU General Public License 3
	@link https://github.com/cseeger-epages/i-doit-go-api
*/

package goidoit

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

// request id
var id int = 0

// basic api interface
type ApiMethods interface {
	// i-doit api request structure
	// as defined in https://kb.i-doit.com/pages/viewpage.action?pageId=7831613
	// also there is a list of methods available
	Request(string, interface{}) (Response, error)

	// search CMDB using a string
	//
	// The search function does handle type assertions
	// for simple output usage
	Search(string) (SearchResponse, error)

	// get object(s) data,
	// single id or slice of id's can be used
	GetObjectsByID([]int) (Response, error)
	/*
		Login()
		Logout()
		IsLoggedIn()
	*/
}

// api struct used for implementing the apiMethods interface
type Api struct {
	url, apikey string
}

type Request struct {
	Version string      `json:"version"`
	Method  string      `json:"method"`
	Params  interface{} `json:"params"`
	Id      int         `json:"id"`
}

// i-doit api response structure
type Response struct {
	Jsonrpc string      `json:"jsonrpc"`
	Result  interface{} `json:"result"`
	Error   IdoitError  `json:"error"`
}

// i-doit api response structure used for search requests
//
// the map is used to handle type assertions
type SearchResponse struct {
	Jsonrpc string
	Result  []map[string]interface{}
	Error   IdoitError
}

// i-doit api error structure
type IdoitError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

// Apikey used for requests
type Apikey struct {
	Apikey string `json:"apikey"`
}

// api constructor
func Newapi(url string, apikey string) (*Api, error) {
	if len(url) != 0 && len(apikey) != 0 {
		a := Api{url, apikey}
		return &a, nil
	}
	return nil, errors.New("url or apikey empty")
}

func (a Api) Request(method string, parameters interface{}) (Response, error) {

	var params = GetParams(a, parameters)
	id = getID()

	data := Request{
		Version: "2.0",
		Method:  method,
		Params:  params,
		Id:      id,
	}

	dataJson, err := json.Marshal(data)

	// logging tbd
	//fmt.Println("Request: ", string(dataJson))

	req, err := http.NewRequest("POST", a.url, bytes.NewBuffer(dataJson))
	if err != nil {
		fmt.Println("REQUEST ERROR: ", err)
		return Response{}, err
	}
	req.Header.Add("content-type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("REQUEST ERROR: ", err)
		return Response{}, err
	}
	var ret = ParseResponse(resp)
	return ret, nil
}

func (a *Api) Search(query string) (SearchResponse, error) {
	params := struct {
		Query string `json:"q"`
	}{query}
	data, err := a.Request("idoit.search", &params)
	if err != nil {
		return SearchResponse{}, err
	}

	// do type assertions for easy output handling
	ret := SearchResponse{Jsonrpc: data.Jsonrpc, Error: data.Error}

	ret.Error.Data = ""
	if data.Error.Data != nil {
		ret.Error.Data = data.Error.Data.(string)
	}

	results := data.Result.([]interface{})
	for i := range results {
		ret.Result = append(ret.Result, results[i].(map[string]interface{}))
	}
	return ret, nil
}

// increment request id's
func getID() int {
	id++
	return id
}

// append nessesary parameters to user provided one
func GetParams(a Api, parameters interface{}) interface{} {

	var params map[string]string
	apikey := Apikey{a.apikey}

	jsonParameters, err := json.Marshal(parameters)

	if err != nil {
		log.Fatal("JSON ERROR: ", err)
	}

	json.Unmarshal(jsonParameters, &params)
	jsonApikey, err := json.Marshal(apikey)

	if err != nil {
		log.Fatal("JSON ERROR: ", err)
	}

	json.Unmarshal(jsonApikey, &params)

	return params
}

// parse json response
func ParseResponse(resp *http.Response) Response {
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal("PARSING ERROR: ", err)
	}

	// logging tbd
	//fmt.Println("Response: ", string(data))

	var ret Response
	_ = json.Unmarshal(data, &ret)

	return ret
}
<|endoftext|>


<commit_before>package main

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

	"github.com/exercism/cli/configuration"
)

const VERSION = "1.6.0"
const USER_AGENT = "github.com/exercism/cli v" + VERSION

var FetchEndpoints = map[string]string{
	"current":  "/api/v1/user/assignments/current",
	"next":     "/api/v1/user/assignments/next",
	"restore":  "/api/v1/user/assignments/restore",
	"demo":     "/api/v1/assignments/demo",
	"exercise": "/api/v1/assignments",
}

type submitResponse struct {
	Id             string
	Status         string
	Language       string
	Exercise       string
	SubmissionPath string `json:"submission_path"`
	Error          string
}

type submitRequest struct {
	Key  string `json:"key"`
	Code string `json:"code"`
	Path string `json:"path"`
}

func FetchAssignments(config configuration.Config, path string) (as []Assignment, err error) {
	url := fmt.Sprintf("%s%s?key=%s", config.Hostname, path, config.ApiKey)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	if resp.StatusCode != http.StatusOK {
		var apiError struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(body, &apiError)
		if err != nil {
			err = fmt.Errorf("Error parsing API response: [%v]", err)
			return
		}

		err = fmt.Errorf("Error fetching assignments. HTTP Status Code: %d\n%s", resp.StatusCode, apiError.Error)
		return
	}

	var fr struct {
		Assignments []Assignment
	}

	err = json.Unmarshal(body, &fr)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
		return
	}

	return fr.Assignments, err
}

func UnsubmitAssignment(config configuration.Config) (r string, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s?key=%s", config.Hostname, path, config.ApiKey)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error destroying submission: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusNoContent {

		var ur struct {
			Error string
		}

		err = json.Unmarshal(body, &ur)
		if err != nil {
			return
		}

		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, ur.Error)
		return ur.Error, err
	}

	return
}
func SubmitAssignment(config configuration.Config, filePath string, code []byte) (r submitResponse, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s", config.Hostname, path)

	submission := submitRequest{Key: config.ApiKey, Code: string(code), Path: filePath}
	submissionJson, err := json.Marshal(submission)
	if err != nil {
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(submissionJson))
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error posting assignment: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusCreated {
		err = json.Unmarshal(body, &r)
		if err != nil {
			return
		}
		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, r)
		return
	}

	err = json.Unmarshal(body, &r)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
	}

	return
}
<commit_msg>Bump version<commit_after>package main

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

	"github.com/exercism/cli/configuration"
)

const VERSION = "1.6.1"
const USER_AGENT = "github.com/exercism/cli v" + VERSION

var FetchEndpoints = map[string]string{
	"current":  "/api/v1/user/assignments/current",
	"next":     "/api/v1/user/assignments/next",
	"restore":  "/api/v1/user/assignments/restore",
	"demo":     "/api/v1/assignments/demo",
	"exercise": "/api/v1/assignments",
}

type submitResponse struct {
	Id             string
	Status         string
	Language       string
	Exercise       string
	SubmissionPath string `json:"submission_path"`
	Error          string
}

type submitRequest struct {
	Key  string `json:"key"`
	Code string `json:"code"`
	Path string `json:"path"`
}

func FetchAssignments(config configuration.Config, path string) (as []Assignment, err error) {
	url := fmt.Sprintf("%s%s?key=%s", config.Hostname, path, config.ApiKey)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		err = fmt.Errorf("Error fetching assignments: [%v]", err)
		return
	}

	if resp.StatusCode != http.StatusOK {
		var apiError struct {
			Error string `json:"error"`
		}
		err = json.Unmarshal(body, &apiError)
		if err != nil {
			err = fmt.Errorf("Error parsing API response: [%v]", err)
			return
		}

		err = fmt.Errorf("Error fetching assignments. HTTP Status Code: %d\n%s", resp.StatusCode, apiError.Error)
		return
	}

	var fr struct {
		Assignments []Assignment
	}

	err = json.Unmarshal(body, &fr)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
		return
	}

	return fr.Assignments, err
}

func UnsubmitAssignment(config configuration.Config) (r string, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s?key=%s", config.Hostname, path, config.ApiKey)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error destroying submission: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusNoContent {

		var ur struct {
			Error string
		}

		err = json.Unmarshal(body, &ur)
		if err != nil {
			return
		}

		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, ur.Error)
		return ur.Error, err
	}

	return
}
func SubmitAssignment(config configuration.Config, filePath string, code []byte) (r submitResponse, err error) {
	path := "api/v1/user/assignments"

	url := fmt.Sprintf("%s/%s", config.Hostname, path)

	submission := submitRequest{Key: config.ApiKey, Code: string(code), Path: filePath}
	submissionJson, err := json.Marshal(submission)
	if err != nil {
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(submissionJson))
	if err != nil {
		return
	}

	req.Header.Set("User-Agent", USER_AGENT)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		err = fmt.Errorf("Error posting assignment: [%v]", err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return
	}

	if resp.StatusCode != http.StatusCreated {
		err = json.Unmarshal(body, &r)
		if err != nil {
			return
		}
		err = fmt.Errorf("Status: %d, Error: %v", resp.StatusCode, r)
		return
	}

	err = json.Unmarshal(body, &r)
	if err != nil {
		err = fmt.Errorf("Error parsing API response: [%v]", err)
	}

	return
}
<|endoftext|>


<commit_before>package apidemic

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/pmylund/go-cache"
)

//Version is the version of apidemic. Apidemic uses semver.
const Version = "0.1"

var maxItemTime = cache.DefaultExpiration

var store = func() *cache.Cache {
	c := cache.New(5*time.Minute, 30*time.Second)
	return c
}()

//API is the struct for the json object that is passed to apidemic for registration.
type API struct {
	Endpoint string                 `json:"endpoint"`
	Payload  map[string]interface{} `json:"payload"`
}

// Home renders hopme page. It renders a json response with information about the service.
func Home(w http.ResponseWriter, r *http.Request) {
	details := make(map[string]interface{})
	details["app_name"] = "ApiDemic"
	details["version"] = Version
	details["details"] = "Fake JSON API response"
	RenderJSON(w, http.StatusOK, details)
	return
}

// RenderJSON helder for rndering JSON response, it marshals value into json and writes
// it into w.
func RenderJSON(w http.ResponseWriter, code int, value interface{}) {
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(value)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

//RegisterEndpoint receives API objects and registers them. The payload from the request is
// transformed into a self aware Value that is capable of faking its own attribute.
func RegisterEndpoint(w http.ResponseWriter, r *http.Request) {
	a := API{}
	err := json.NewDecoder(r.Body).Decode(&a)
	if err != nil {
		RenderJSON(w, http.StatusInternalServerError, NewResponse(err.Error()))
		return
	}
	if _, ok := store.Get(a.Endpoint); ok {
		RenderJSON(w, http.StatusOK, NewResponse("endpoint already taken"))
		return
	}
	obj := NewObject()
	err = obj.Load(a.Payload)
	if err != nil {
		RenderJSON(w, http.StatusInternalServerError, NewResponse(err.Error()))
		return
	}
	store.Set(a.Endpoint, obj, maxItemTime)
	RenderJSON(w, http.StatusOK, NewResponse("cool"))
}

//GetEndpoint renders registered endpoints.
func GetEndpoint(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	endpoint := vars["endpoint"]
	if eVal, ok := store.Get(endpoint); ok {
		RenderJSON(w, http.StatusOK, eVal)
		return
	}
	RenderJSON(w, http.StatusNotFound, NewResponse("apidemic: "+endpoint+" is not found"))
}

//NewResponse helper for response JSON message
func NewResponse(message string) interface{} {
	return struct {
		Text string `json:"text"`
	}{
		message,
	}
}

//NewServer returns a new apidemic server
func NewServer() *mux.Router {
	m := mux.NewRouter()
	m.HandleFunc("/", Home)
	m.HandleFunc("/register", RegisterEndpoint).Methods("POST")
	m.HandleFunc("/api/{endpoint}", GetEndpoint).Methods("GET")
	return m
}
<commit_msg>Bymp to version 0.2<commit_after>package apidemic

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/pmylund/go-cache"
)

//Version is the version of apidemic. Apidemic uses semver.
const Version = "0.2"

var maxItemTime = cache.DefaultExpiration

var store = func() *cache.Cache {
	c := cache.New(5*time.Minute, 30*time.Second)
	return c
}()

//API is the struct for the json object that is passed to apidemic for registration.
type API struct {
	Endpoint string                 `json:"endpoint"`
	Payload  map[string]interface{} `json:"payload"`
}

// Home renders hopme page. It renders a json response with information about the service.
func Home(w http.ResponseWriter, r *http.Request) {
	details := make(map[string]interface{})
	details["app_name"] = "ApiDemic"
	details["version"] = Version
	details["details"] = "Fake JSON API response"
	RenderJSON(w, http.StatusOK, details)
	return
}

// RenderJSON helder for rndering JSON response, it marshals value into json and writes
// it into w.
func RenderJSON(w http.ResponseWriter, code int, value interface{}) {
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(value)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

//RegisterEndpoint receives API objects and registers them. The payload from the request is
// transformed into a self aware Value that is capable of faking its own attribute.
func RegisterEndpoint(w http.ResponseWriter, r *http.Request) {
	a := API{}
	err := json.NewDecoder(r.Body).Decode(&a)
	if err != nil {
		RenderJSON(w, http.StatusInternalServerError, NewResponse(err.Error()))
		return
	}
	if _, ok := store.Get(a.Endpoint); ok {
		RenderJSON(w, http.StatusOK, NewResponse("endpoint already taken"))
		return
	}
	obj := NewObject()
	err = obj.Load(a.Payload)
	if err != nil {
		RenderJSON(w, http.StatusInternalServerError, NewResponse(err.Error()))
		return
	}
	store.Set(a.Endpoint, obj, maxItemTime)
	RenderJSON(w, http.StatusOK, NewResponse("cool"))
}

//GetEndpoint renders registered endpoints.
func GetEndpoint(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	endpoint := vars["endpoint"]
	if eVal, ok := store.Get(endpoint); ok {
		RenderJSON(w, http.StatusOK, eVal)
		return
	}
	RenderJSON(w, http.StatusNotFound, NewResponse("apidemic: "+endpoint+" is not found"))
}

//NewResponse helper for response JSON message
func NewResponse(message string) interface{} {
	return struct {
		Text string `json:"text"`
	}{
		message,
	}
}

//NewServer returns a new apidemic server
func NewServer() *mux.Router {
	m := mux.NewRouter()
	m.HandleFunc("/", Home)
	m.HandleFunc("/register", RegisterEndpoint).Methods("POST")
	m.HandleFunc("/api/{endpoint}", GetEndpoint).Methods("GET")
	return m
}
<|endoftext|>


<commit_before>// Package fbapi provides wrappers to access the Facebook API.
package fbapi

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/nshah/go.fburl"
	"github.com/nshah/go.httpcontrol"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const redactedStub = "$1=-- XX -- REDACTED -- XX --"

var (
	insecureSSL = flag.Bool(
		"fbapi.insecure", false, "Skip SSL certificate validation.")
	redact = flag.Bool(
		"fbapi.redact",
		true,
		"When true known sensitive information will be stripped from errors.")
	timeout = flag.Duration(
		"fbapi.timeout",
		5*time.Second,
		"Timeout for http requests.")
	maxTries = flag.Uint(
		"fbapi.max-tries",
		3,
		"Number of retries for known safe to retry calls.")
	cleanURLRegExp  = regexp.MustCompile("(access_token|client_secret)=([^&]*)")
	httpClientCache *http.Client
)

// An Error from the API.
type Error struct {
	Message string `json:"message"`
	Type    string `json:"type"`
	Code    int    `json:"code"`
	Body    []byte
}

// Wrapper for "error"
type errorResponse struct {
	Error Error `json:"error"`
}

// Represents a thing that wants to modify the url.Values.
type Values interface {
	Set(url.Values)
}

// Represents an "access_token" for the Facebook API.
type Token string

const (
	PublicToken = Token("")
)

// Generic Page options for list type queries.
type Page struct {
	Limit  int
	Offset int
}

// Set the corresponding values for the Page.
func (page Page) Set(values url.Values) {
	if page.Limit != 0 {
		values.Set("limit", strconv.Itoa(page.Limit))
	}
	if page.Offset != 0 {
		values.Set("offset", strconv.Itoa(page.Offset))
	}
}

// A slice of field names.
type Fields []string

// For selecting fields.
func (fields Fields) Set(values url.Values) {
	if len(fields) > 0 {
		values.Set("fields", strings.Join(fields, ","))
	}
}

// Set the token if necessary.
func (token Token) Set(values url.Values) {
	if token != PublicToken {
		values.Set("access_token", string(token))
	}
}

// String representation as defined by the error interface.
func (e *Error) Error() string {
	return fmt.Sprintf("API call failed with error body:\n%s", string(e.Body))
}

// Disable SSL cert, useful when debugging or hitting internal self-signed certs
func httpClient() *http.Client {
	if httpClientCache == nil {
		httpClientCache = &http.Client{
			Transport: &httpcontrol.Control{
				Transport: &http.Transport{
					Proxy:           http.ProxyFromEnvironment,
					TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecureSSL},
				},
				Timeout:  *timeout,
				MaxTries: *maxTries,
			},
		}
	}
	return httpClientCache
}

// remove known sensitive tokens from data
func cleanURL(url string) string {
	if *redact {
		return cleanURLRegExp.ReplaceAllString(url, redactedStub)
	}
	return url
}

// Make a GET Graph API request and get the raw body byte slice.
func GetRaw(path string, values url.Values) ([]byte, error) {
	const phpRFC3339 = `Y-m-d\TH:i:s\Z`
	values.Set("date_format", phpRFC3339)
	u := &fburl.URL{
		Scheme:    "https",
		SubDomain: fburl.DGraph,
		Path:      path,
		Values:    values,
	}
	resp, err := httpClient().Get(u.String())
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed with error %s.", cleanURL(u.String()), err)
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed because body could not be read "+
				"with error %s.",
			cleanURL(u.String()), err)
	}
	if resp.StatusCode > 399 || resp.StatusCode < 200 {
		apiError := &errorResponse{Error{Body: b}}
		err = json.Unmarshal(b, apiError)
		if err != nil {
			return nil, fmt.Errorf(
				"Parsing error response failed with %s:\n%s", err, string(b))
		}
		return nil, &apiError.Error
	}
	return b, nil
}

// Make a GET Graph API request.
func Get(result interface{}, path string, values ...Values) error {
	final := url.Values{}
	for _, v := range values {
		v.Set(final)
	}
	b, err := GetRaw(path, final)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, result)
	if err != nil {
		return fmt.Errorf(
			"Request for path %s with response %s failed with "+
				"json.Unmarshal error %s.",
			cleanURL(path), string(b), err)
	}
	return nil
}
<commit_msg>reckless username change<commit_after>// Package fbapi provides wrappers to access the Facebook API.
package fbapi

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/daaku/go.fburl"
	"github.com/daaku/go.httpcontrol"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const redactedStub = "$1=-- XX -- REDACTED -- XX --"

var (
	insecureSSL = flag.Bool(
		"fbapi.insecure", false, "Skip SSL certificate validation.")
	redact = flag.Bool(
		"fbapi.redact",
		true,
		"When true known sensitive information will be stripped from errors.")
	timeout = flag.Duration(
		"fbapi.timeout",
		5*time.Second,
		"Timeout for http requests.")
	maxTries = flag.Uint(
		"fbapi.max-tries",
		3,
		"Number of retries for known safe to retry calls.")
	cleanURLRegExp  = regexp.MustCompile("(access_token|client_secret)=([^&]*)")
	httpClientCache *http.Client
)

// An Error from the API.
type Error struct {
	Message string `json:"message"`
	Type    string `json:"type"`
	Code    int    `json:"code"`
	Body    []byte
}

// Wrapper for "error"
type errorResponse struct {
	Error Error `json:"error"`
}

// Represents a thing that wants to modify the url.Values.
type Values interface {
	Set(url.Values)
}

// Represents an "access_token" for the Facebook API.
type Token string

const (
	PublicToken = Token("")
)

// Generic Page options for list type queries.
type Page struct {
	Limit  int
	Offset int
}

// Set the corresponding values for the Page.
func (page Page) Set(values url.Values) {
	if page.Limit != 0 {
		values.Set("limit", strconv.Itoa(page.Limit))
	}
	if page.Offset != 0 {
		values.Set("offset", strconv.Itoa(page.Offset))
	}
}

// A slice of field names.
type Fields []string

// For selecting fields.
func (fields Fields) Set(values url.Values) {
	if len(fields) > 0 {
		values.Set("fields", strings.Join(fields, ","))
	}
}

// Set the token if necessary.
func (token Token) Set(values url.Values) {
	if token != PublicToken {
		values.Set("access_token", string(token))
	}
}

// String representation as defined by the error interface.
func (e *Error) Error() string {
	return fmt.Sprintf("API call failed with error body:\n%s", string(e.Body))
}

// Disable SSL cert, useful when debugging or hitting internal self-signed certs
func httpClient() *http.Client {
	if httpClientCache == nil {
		httpClientCache = &http.Client{
			Transport: &httpcontrol.Control{
				Transport: &http.Transport{
					Proxy:           http.ProxyFromEnvironment,
					TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecureSSL},
				},
				Timeout:  *timeout,
				MaxTries: *maxTries,
			},
		}
	}
	return httpClientCache
}

// remove known sensitive tokens from data
func cleanURL(url string) string {
	if *redact {
		return cleanURLRegExp.ReplaceAllString(url, redactedStub)
	}
	return url
}

// Make a GET Graph API request and get the raw body byte slice.
func GetRaw(path string, values url.Values) ([]byte, error) {
	const phpRFC3339 = `Y-m-d\TH:i:s\Z`
	values.Set("date_format", phpRFC3339)
	u := &fburl.URL{
		Scheme:    "https",
		SubDomain: fburl.DGraph,
		Path:      path,
		Values:    values,
	}
	resp, err := httpClient().Get(u.String())
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed with error %s.", cleanURL(u.String()), err)
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed because body could not be read "+
				"with error %s.",
			cleanURL(u.String()), err)
	}
	if resp.StatusCode > 399 || resp.StatusCode < 200 {
		apiError := &errorResponse{Error{Body: b}}
		err = json.Unmarshal(b, apiError)
		if err != nil {
			return nil, fmt.Errorf(
				"Parsing error response failed with %s:\n%s", err, string(b))
		}
		return nil, &apiError.Error
	}
	return b, nil
}

// Make a GET Graph API request.
func Get(result interface{}, path string, values ...Values) error {
	final := url.Values{}
	for _, v := range values {
		v.Set(final)
	}
	b, err := GetRaw(path, final)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, result)
	if err != nil {
		return fmt.Errorf(
			"Request for path %s with response %s failed with "+
				"json.Unmarshal error %s.",
			cleanURL(path), string(b), err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net"
	"strings"
)

// Returns client authentication token from header or url params
func getClientToken(c *gin.Context) string {
	// Try fetching auth token from headers first
	token := c.Request.Header.Get("Token")

	// Try to fetch from url param if blank
	if token == "" {
		if len(c.Request.URL.Query()["token"]) > 0 {
			token = c.Request.URL.Query()["token"][0]
		}
	}

	return token
}

// Returns a list of all available services
func renderAvailableServices(c *gin.Context) {
	// Check if authentication is enabled
	if options.Auth {
		token := getClientToken(c)

		if token != options.Token {
			c.String(401, "Invalid token")
			c.Abort()
			return
		}
	}

	names := []string{}
	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

// Returns a list of all service environments
func renderServiceEnvironments(c *gin.Context) {
	// Check if authentication is enabled
	if options.Auth {
		token := getClientToken(c)

		if token != options.Token {
			c.String(401, "Invalid token")
			c.Abort()
			return
		}
	}

	serviceName := c.Params.ByName("service")
	service, err := getService(serviceName)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	// Respond with 400 if service does not exist
	// Todo: maybe respond with 404
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Get remote IP address
	host, _, err := net.SplitHostPort(c.Request.RemoteAddr)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Check if environment has allowed hosts. Localhost is allowed.
	if host != "::1" && len(environment.Hosts) > 0 {
		// Reject requests from non-whitelisted hosts
		if environment.HostEnabled(host) == false {
			c.String(401, "Restricted\n")
			return
		}
	}

	// Fetch token from url param or from the header
	token := getClientToken(c)

	// Validate environment token if its set, otherwise check agains global token
	if environment.Token != "" {
		if token != environment.Token {
			c.String(401, "Restricted\n")
			return
		}
	} else {
		if options.Auth && token != options.Token {
			c.String(401, "Restricted\n")
			return
		}
	}

	c.String(200, environment.ToString()+"\n")
}

func startServer() {
	host := fmt.Sprintf("%s:%d", options.Host, options.Port)
	api := gin.Default()

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)

	if options.Auth {
		fmt.Println("authentication enabled")
	}

	fmt.Println("starting server on", host)
	api.Run(host)
}
<commit_msg>Go fmt<commit_after>package main

import (
	"fmt"
	"net"
	"strings"

	"github.com/gin-gonic/gin"
)

// Returns client authentication token from header or url params
func getClientToken(c *gin.Context) string {
	// Try fetching auth token from headers first
	token := c.Request.Header.Get("Token")

	// Try to fetch from url param if blank
	if token == "" {
		if len(c.Request.URL.Query()["token"]) > 0 {
			token = c.Request.URL.Query()["token"][0]
		}
	}

	return token
}

// Returns a list of all available services
func renderAvailableServices(c *gin.Context) {
	// Check if authentication is enabled
	if options.Auth {
		token := getClientToken(c)

		if token != options.Token {
			c.String(401, "Invalid token")
			c.Abort()
			return
		}
	}

	names := []string{}
	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

// Returns a list of all service environments
func renderServiceEnvironments(c *gin.Context) {
	// Check if authentication is enabled
	if options.Auth {
		token := getClientToken(c)

		if token != options.Token {
			c.String(401, "Invalid token")
			c.Abort()
			return
		}
	}

	serviceName := c.Params.ByName("service")
	service, err := getService(serviceName)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	// Respond with 400 if service does not exist
	// Todo: maybe respond with 404
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Get remote IP address
	host, _, err := net.SplitHostPort(c.Request.RemoteAddr)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Check if environment has allowed hosts. Localhost is allowed.
	if host != "::1" && len(environment.Hosts) > 0 {
		// Reject requests from non-whitelisted hosts
		if environment.HostEnabled(host) == false {
			c.String(401, "Restricted\n")
			return
		}
	}

	// Fetch token from url param or from the header
	token := getClientToken(c)

	// Validate environment token if its set, otherwise check agains global token
	if environment.Token != "" {
		if token != environment.Token {
			c.String(401, "Restricted\n")
			return
		}
	} else {
		if options.Auth && token != options.Token {
			c.String(401, "Restricted\n")
			return
		}
	}

	c.String(200, environment.ToString()+"\n")
}

func startServer() {
	host := fmt.Sprintf("%s:%d", options.Host, options.Port)
	api := gin.Default()

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)

	if options.Auth {
		fmt.Println("authentication enabled")
	}

	fmt.Println("starting server on", host)
	api.Run(host)
}
<|endoftext|>


<commit_before>// vim: ts=8 sw=8 noet ai

package perigee

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

// The UnexpectedResponseCodeError structure represents a mismatch in understanding between server and client in terms of response codes.
// Most often, this is due to an actual error condition (e.g., getting a 404 for a resource when you expect a 200).
// However, it needn't always be the case (e.g., getting a 204 (No Content) response back when a 200 is expected).
type UnexpectedResponseCodeError struct {
	Url      string
	Expected []int
	Actual   int
	Body     []byte
}

func (err *UnexpectedResponseCodeError) Error() string {
	return fmt.Sprintf("Expected HTTP response code %d when accessing URL(%s); got %d instead with the following body:\n%s", err.Expected, err.Url, err.Actual, string(err.Body))
}

// Request issues an HTTP request, marshaling parameters, and unmarshaling results, as configured in the provided Options parameter.
// The Response structure returned, if any, will include accumulated results recovered from the HTTP server.
// See the Response structure for more details.
func Request(method string, url string, opts Options) (*Response, error) {
	var body io.Reader
	var response Response

	client := opts.CustomClient
	if client == nil {
		client = new(http.Client)
	}

	contentType := opts.ContentType
	if contentType == "" {
		contentType = "application/json"
	}

	accept := opts.Accept
	if accept == "" {
		accept = "application/json"
	}

	body = nil
	if opts.ReqBody != nil {
		if contentType == "application/json" {
			bodyText, err := json.Marshal(opts.ReqBody)
			if err != nil {
				return nil, err
			}
			body = strings.NewReader(string(bodyText))
			if opts.DumpReqJson {
				log.Printf("Making request:\n%#v\n", string(bodyText))
			}
		} else {
			// assume opts.ReqBody implements the correct interface
			body = opts.ReqBody.(io.Reader)
		}
	}

	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", contentType)
	req.Header.Add("Accept", accept)

	if opts.ContentLength > 0 {
		req.ContentLength = opts.ContentLength
		req.Header.Add("Content-Length", string(opts.ContentLength))
	}

	if opts.MoreHeaders != nil {
		for k, v := range opts.MoreHeaders {
			req.Header.Add(k, v)
		}
	}

	if opts.SetHeaders != nil {
		err = opts.SetHeaders(req)
		if err != nil {
			return &response, err
		}
	}

	httpResponse, err := client.Do(req)
	if httpResponse != nil {
		response.HttpResponse = *httpResponse
		response.StatusCode = httpResponse.StatusCode
	}

	if err != nil {
		return &response, err
	}
	// This if-statement is legacy code, preserved for backward compatibility.
	if opts.StatusCode != nil {
		*opts.StatusCode = httpResponse.StatusCode
	}

	acceptableResponseCodes := opts.OkCodes
	if len(acceptableResponseCodes) != 0 {
		if not_in(httpResponse.StatusCode, acceptableResponseCodes) {
			b, _ := ioutil.ReadAll(httpResponse.Body)
			httpResponse.Body.Close()
			return &response, &UnexpectedResponseCodeError{
				Url:      url,
				Expected: acceptableResponseCodes,
				Actual:   httpResponse.StatusCode,
				Body:     b,
			}
		}
	}
	if opts.Results != nil {
		defer httpResponse.Body.Close()
		jsonResult, err := ioutil.ReadAll(httpResponse.Body)
		response.JsonResult = jsonResult
		if err != nil {
			return &response, err
		}

		err = json.Unmarshal(jsonResult, opts.Results)
		// This if-statement is legacy code, preserved for backward compatibility.
		if opts.ResponseJson != nil {
			*opts.ResponseJson = jsonResult
		}
	}
	return &response, err
}

// not_in returns false if, and only if, the provided needle is _not_
// in the given set of integers.
func not_in(needle int, haystack []int) bool {
	for _, straw := range haystack {
		if needle == straw {
			return false
		}
	}
	return true
}

// Post makes a POST request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Post(url string, opts Options) error {
	r, err := Request("POST", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Get makes a GET request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Get(url string, opts Options) error {
	r, err := Request("GET", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Delete makes a DELETE request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Delete(url string, opts Options) error {
	r, err := Request("DELETE", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Put makes a PUT request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Put(url string, opts Options) error {
	r, err := Request("PUT", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Options describes a set of optional parameters to the various request calls.
//
// The custom client can be used for a variety of purposes beyond selecting encrypted versus unencrypted channels.
// Transports can be defined to provide augmented logging, header manipulation, et. al.
//
// If the ReqBody field is provided, it will be embedded as a JSON object.
// Otherwise, provide nil.
//
// If JSON output is to be expected from the response,
// provide either a pointer to the container structure in Results,
// or a pointer to a nil-initialized pointer variable.
// The latter method will cause the unmarshaller to allocate the container type for you.
// If no response is expected, provide a nil Results value.
//
// The MoreHeaders map, if non-nil or empty, provides a set of headers to add to those
// already present in the request.  At present, only Accepted and Content-Type are set
// by default.
//
// OkCodes provides a set of acceptable, positive responses.
//
// If provided, StatusCode specifies a pointer to an integer, which will receive the
// returned HTTP status code, successful or not.  DEPRECATED; use the Response.StatusCode field instead for new software.
//
// ResponseJson, if specified, provides a means for returning the raw JSON.  This is
// most useful for diagnostics.  DEPRECATED; use the Response.JsonResult field instead for new software.
//
// DumpReqJson, if set to true, will cause the request to appear to stdout for debugging purposes.
// This attribute may be removed at any time in the future; DO NOT use this attribute in production software.
//
// Response, if set, provides a way to communicate the complete set of HTTP response, raw JSON, status code, and
// other useful attributes back to the caller.  Note that the Request() method returns a Response structure as part
// of its public interface; you don't need to set the Response field here to use this structure.  The Response field
// exists primarily for legacy or deprecated functions.
//
// SetHeaders allows the caller to provide code to set any custom headers programmatically.  Typically, this
// facility can invoke, e.g., SetBasicAuth() on the request to easily set up authentication.
// Any error generated will terminate the request and will propegate back to the caller.
type Options struct {
	CustomClient  *http.Client
	ReqBody       interface{}
	Results       interface{}
	MoreHeaders   map[string]string
	OkCodes       []int
	StatusCode    *int    `DEPRECATED`
	DumpReqJson   bool    `UNSUPPORTED`
	ResponseJson  *[]byte `DEPRECATED`
	Response      **Response
	ContentType   string `json:"Content-Type,omitempty"`
	ContentLength int64  `json:"Content-Length,omitempty"`
	Accept        string `json:"Accept,omitempty"`
	SetHeaders    func(r *http.Request) error
}

// Response contains return values from the various request calls.
//
// HttpResponse will return the http response from the request call.
// Note: HttpResponse.Body is always closed and will not be available from this return value.
//
// StatusCode specifies the returned HTTP status code, successful or not.
//
// If Results is specified in the Options:
// - JsonResult will contain the raw return from the request call
//   This is most useful for diagnostics.
// - Result will contain the unmarshalled json either in the Result passed in
//   or the unmarshaller will allocate the container type for you.

type Response struct {
	HttpResponse http.Response
	JsonResult   []byte
	Results      interface{}
	StatusCode   int
}
<commit_msg>Ensuring that bodiless requests aren't sent with Content or Accept headers<commit_after>// vim: ts=8 sw=8 noet ai

package perigee

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

// The UnexpectedResponseCodeError structure represents a mismatch in understanding between server and client in terms of response codes.
// Most often, this is due to an actual error condition (e.g., getting a 404 for a resource when you expect a 200).
// However, it needn't always be the case (e.g., getting a 204 (No Content) response back when a 200 is expected).
type UnexpectedResponseCodeError struct {
	Url      string
	Expected []int
	Actual   int
	Body     []byte
}

func (err *UnexpectedResponseCodeError) Error() string {
	return fmt.Sprintf("Expected HTTP response code %d when accessing URL(%s); got %d instead with the following body:\n%s", err.Expected, err.Url, err.Actual, string(err.Body))
}

// Request issues an HTTP request, marshaling parameters, and unmarshaling results, as configured in the provided Options parameter.
// The Response structure returned, if any, will include accumulated results recovered from the HTTP server.
// See the Response structure for more details.
func Request(method string, url string, opts Options) (*Response, error) {
	var body io.Reader
	var response Response

	client := opts.CustomClient
	if client == nil {
		client = new(http.Client)
	}

	contentType := opts.ContentType
	accept := opts.Accept

	body = nil
	if opts.ReqBody != nil {
		if contentType == "" {
			contentType = "application/json"
		}
		if accept == "" {
			accept = "application/json"
		}

		if contentType == "application/json" {
			bodyText, err := json.Marshal(opts.ReqBody)
			if err != nil {
				return nil, err
			}
			body = strings.NewReader(string(bodyText))
			if opts.DumpReqJson {
				log.Printf("Making request:\n%#v\n", string(bodyText))
			}
		} else {
			// assume opts.ReqBody implements the correct interface
			body = opts.ReqBody.(io.Reader)
		}
	}

	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	if contentType != "" {
		req.Header.Add("Content-Type", contentType)
	}

	if accept != "" {
		req.Header.Add("Accept", accept)
	}

	if opts.ContentLength > 0 {
		req.ContentLength = opts.ContentLength
		req.Header.Add("Content-Length", string(opts.ContentLength))
	}

	if opts.MoreHeaders != nil {
		for k, v := range opts.MoreHeaders {
			req.Header.Add(k, v)
		}
	}

	if opts.SetHeaders != nil {
		err = opts.SetHeaders(req)
		if err != nil {
			return &response, err
		}
	}

	httpResponse, err := client.Do(req)
	if httpResponse != nil {
		response.HttpResponse = *httpResponse
		response.StatusCode = httpResponse.StatusCode
	}

	if err != nil {
		return &response, err
	}
	// This if-statement is legacy code, preserved for backward compatibility.
	if opts.StatusCode != nil {
		*opts.StatusCode = httpResponse.StatusCode
	}

	acceptableResponseCodes := opts.OkCodes
	if len(acceptableResponseCodes) != 0 {
		if not_in(httpResponse.StatusCode, acceptableResponseCodes) {
			b, _ := ioutil.ReadAll(httpResponse.Body)
			httpResponse.Body.Close()
			return &response, &UnexpectedResponseCodeError{
				Url:      url,
				Expected: acceptableResponseCodes,
				Actual:   httpResponse.StatusCode,
				Body:     b,
			}
		}
	}
	if opts.Results != nil {
		defer httpResponse.Body.Close()
		jsonResult, err := ioutil.ReadAll(httpResponse.Body)
		response.JsonResult = jsonResult
		if err != nil {
			return &response, err
		}

		err = json.Unmarshal(jsonResult, opts.Results)
		// This if-statement is legacy code, preserved for backward compatibility.
		if opts.ResponseJson != nil {
			*opts.ResponseJson = jsonResult
		}
	}
	return &response, err
}

// not_in returns false if, and only if, the provided needle is _not_
// in the given set of integers.
func not_in(needle int, haystack []int) bool {
	for _, straw := range haystack {
		if needle == straw {
			return false
		}
	}
	return true
}

// Post makes a POST request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Post(url string, opts Options) error {
	r, err := Request("POST", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Get makes a GET request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Get(url string, opts Options) error {
	r, err := Request("GET", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Delete makes a DELETE request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Delete(url string, opts Options) error {
	r, err := Request("DELETE", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Put makes a PUT request against a server using the provided HTTP client.
// The url must be a fully-formed URL string.
// DEPRECATED.  Use Request() instead.
func Put(url string, opts Options) error {
	r, err := Request("PUT", url, opts)
	if opts.Response != nil {
		*opts.Response = r
	}
	return err
}

// Options describes a set of optional parameters to the various request calls.
//
// The custom client can be used for a variety of purposes beyond selecting encrypted versus unencrypted channels.
// Transports can be defined to provide augmented logging, header manipulation, et. al.
//
// If the ReqBody field is provided, it will be embedded as a JSON object.
// Otherwise, provide nil.
//
// If JSON output is to be expected from the response,
// provide either a pointer to the container structure in Results,
// or a pointer to a nil-initialized pointer variable.
// The latter method will cause the unmarshaller to allocate the container type for you.
// If no response is expected, provide a nil Results value.
//
// The MoreHeaders map, if non-nil or empty, provides a set of headers to add to those
// already present in the request.  At present, only Accepted and Content-Type are set
// by default.
//
// OkCodes provides a set of acceptable, positive responses.
//
// If provided, StatusCode specifies a pointer to an integer, which will receive the
// returned HTTP status code, successful or not.  DEPRECATED; use the Response.StatusCode field instead for new software.
//
// ResponseJson, if specified, provides a means for returning the raw JSON.  This is
// most useful for diagnostics.  DEPRECATED; use the Response.JsonResult field instead for new software.
//
// DumpReqJson, if set to true, will cause the request to appear to stdout for debugging purposes.
// This attribute may be removed at any time in the future; DO NOT use this attribute in production software.
//
// Response, if set, provides a way to communicate the complete set of HTTP response, raw JSON, status code, and
// other useful attributes back to the caller.  Note that the Request() method returns a Response structure as part
// of its public interface; you don't need to set the Response field here to use this structure.  The Response field
// exists primarily for legacy or deprecated functions.
//
// SetHeaders allows the caller to provide code to set any custom headers programmatically.  Typically, this
// facility can invoke, e.g., SetBasicAuth() on the request to easily set up authentication.
// Any error generated will terminate the request and will propegate back to the caller.
type Options struct {
	CustomClient  *http.Client
	ReqBody       interface{}
	Results       interface{}
	MoreHeaders   map[string]string
	OkCodes       []int
	StatusCode    *int    `DEPRECATED`
	DumpReqJson   bool    `UNSUPPORTED`
	ResponseJson  *[]byte `DEPRECATED`
	Response      **Response
	ContentType   string `json:"Content-Type,omitempty"`
	ContentLength int64  `json:"Content-Length,omitempty"`
	Accept        string `json:"Accept,omitempty"`
	SetHeaders    func(r *http.Request) error
}

// Response contains return values from the various request calls.
//
// HttpResponse will return the http response from the request call.
// Note: HttpResponse.Body is always closed and will not be available from this return value.
//
// StatusCode specifies the returned HTTP status code, successful or not.
//
// If Results is specified in the Options:
// - JsonResult will contain the raw return from the request call
//   This is most useful for diagnostics.
// - Result will contain the unmarshalled json either in the Result passed in
//   or the unmarshaller will allocate the container type for you.

type Response struct {
	HttpResponse http.Response
	JsonResult   []byte
	Results      interface{}
	StatusCode   int
}
<|endoftext|>


<commit_before><commit_msg>Don't pass SinceSeconds as this seems to cause logs to sometimes not appear.<commit_after><|endoftext|>


<commit_before>package app

import (
	"bytes"
	"image"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"

	_ "image/jpeg"
	_ "image/png"

	fb "github.com/huandu/facebook"

	"appengine"
	"appengine/datastore"
	"appengine/urlfetch"
)

var FbApp = fb.New("526791527487217", "e314e5fc761425d59ea9e2666c63e108")
var aboutParams = fb.Params{
	"method":       fb.GET,
	"relative_url": "me",
	"fields":       "name,email,gender,age_range,hometown",
}

var photoParams = fb.Params{
	"method":       fb.GET,
	"relative_url": "me/picture?width=320&height=320&redirect=false",
}

func init() {
	http.HandleFunc("/static/", StaticHandler)
	http.HandleFunc("/", MainHandler)

	fb.Debug = fb.DEBUG_ALL
	FbApp.EnableAppsecretProof = true
}

func StaticHandler(w http.ResponseWriter, r *http.Request) {
	path := "." + r.URL.Path

	if f, err := os.Stat(path); err == nil && !f.IsDir() {
		http.ServeFile(w, r, path)
		return
	}

	http.NotFound(w, r)
}

func MainHandler(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.URL.Path != "/":
		http.NotFound(w, r)
	case r.Method == "GET":
		handleGet(w, r)
	case r.Method == "POST":
		handlePost(w, r)
	}

	return
}

func handleGet(w http.ResponseWriter, r *http.Request) {
	context := appengine.NewContext(r)
	data, err := ioutil.ReadFile("index.html")
	check(err, context)
	w.Write(data)
}

type Log struct {
	Name     string
	Gender   string
	Party    string
	Email    string
	AgeRange string
	Hometown string
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	context := appengine.NewContext(r)

	r.ParseForm()
	access_token := r.FormValue("access_token")
	party := r.FormValue("party")
	context.Infof("party = %s", party)

	session := FbApp.Session(access_token)
	session.HttpClient = urlfetch.Client(context)
	err := session.Validate()
	check(err, context)

	results, err := session.BatchApi(aboutParams, photoParams)
	check(err, context)

	aboutBatch, err := results[0].Batch()
	check(err, context)
	photoBatch, err := results[1].Batch()
	check(err, context)

	aboutResp := aboutBatch.Result
	photoResp := photoBatch.Result

	SaveAboutUser(&aboutResp, context)
	profilePicture := GetUserPhoto(&photoResp, context)

	imagebytes := addLogo(profilePicture, party, context)
	form, mime := CreateImageForm(imagebytes, context, r.Host)

	url := "https://graph.facebook.com/me/photos" +
		"?access_token=" + access_token +
		"&appsecret_proof=" + session.AppsecretProof()
	//+ "&no_story=true"

	uploadResquest, _ := http.NewRequest("POST", url, &form)
	uploadResquest.Header.Set("Content-Type", mime)
	uploadResp, _ := session.Request(uploadResquest)
	check(err, context)

	var photoID string
	uploadResp.DecodeField("id", &photoID)
	redirectUrl := "https://facebook.com/photo.php?fbid=" + photoID + "&makeprofile=1&prof"
	http.Redirect(w, r, redirectUrl, 303)
}

func SaveAboutUser(aboutResp *fb.Result, context appengine.Context) {
	var log Log
	aboutResp.Decode(&log)

	var ageRange map[string]string
	aboutResp.DecodeField("age_range", &ageRange)
	log.AgeRange = ageRange["min"]

	_, err := datastore.Put(context,
		datastore.NewIncompleteKey(context, "log", nil),
		&log)
	check(err, context)
}

func GetUserPhoto(photoResp *fb.Result, context appengine.Context) *image.Image {
	var dataField fb.Result
	photoResp.DecodeField("data", &dataField)

	var url string
	dataField.DecodeField("url", &url)

	client := urlfetch.Client(context)
	resp, err := client.Get(url)
	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	check(err, context)

	reader := bytes.NewReader(data)
	profilePicture, _, err := image.Decode(reader)
	check(err, context)

	return &profilePicture
}

func CreateImageForm(imageBytes []byte, context appengine.Context, host string) (bytes.Buffer, string) {
	var formBuffer bytes.Buffer
	multiWriter := multipart.NewWriter(&formBuffer)

	imageField, err := multiWriter.CreateFormFile("source", "election.png")
	check(err, context)

	imageBuffer := bytes.NewBuffer(imageBytes)
	_, err = io.Copy(imageField, imageBuffer)
	check(err, context)

	messageField, err := multiWriter.CreateFormField("caption")
	check(err, context)
	_, err = messageField.Write([]byte("Created at http://" + host))
	check(err, context)

	multiWriter.Close()

	return formBuffer, multiWriter.FormDataContentType()
}
<commit_msg>added privacy url<commit_after>package app

import (
	"bytes"
	"image"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"

	_ "image/jpeg"
	_ "image/png"

	fb "github.com/huandu/facebook"

	"appengine"
	"appengine/datastore"
	"appengine/urlfetch"
)

var FbApp = fb.New("526791527487217", "e314e5fc761425d59ea9e2666c63e108")
var aboutParams = fb.Params{
	"method":       fb.GET,
	"relative_url": "me",
	"fields":       "name,email,gender,age_range,hometown",
}

var photoParams = fb.Params{
	"method":       fb.GET,
	"relative_url": "me/picture?width=320&height=320&redirect=false",
}

func init() {
	http.HandleFunc("/static/", StaticHandler)
	http.HandleFunc("/", MainHandler)

	fb.Debug = fb.DEBUG_ALL
	FbApp.EnableAppsecretProof = true
}

func StaticHandler(w http.ResponseWriter, r *http.Request) {
	path := "." + r.URL.Path

	if f, err := os.Stat(path); err == nil && !f.IsDir() {
		http.ServeFile(w, r, path)
		return
	}

	http.NotFound(w, r)
}

func MainHandler(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.URL.Path == "/privacy":
		w.Write([]byte("Coming Soon"))
	case r.URL.Path != "/":
		http.NotFound(w, r)
	case r.Method == "GET":
		handleGet(w, r)
	case r.Method == "POST":
		handlePost(w, r)
	}

	return
}

func handleGet(w http.ResponseWriter, r *http.Request) {
	context := appengine.NewContext(r)
	data, err := ioutil.ReadFile("index.html")
	check(err, context)
	w.Write(data)
}

type Log struct {
	Name     string
	Gender   string
	Party    string
	Email    string
	AgeRange string
	Hometown string
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	context := appengine.NewContext(r)

	r.ParseForm()
	access_token := r.FormValue("access_token")
	party := r.FormValue("party")
	context.Infof("party = %s", party)

	session := FbApp.Session(access_token)
	session.HttpClient = urlfetch.Client(context)
	err := session.Validate()
	check(err, context)

	results, err := session.BatchApi(aboutParams, photoParams)
	check(err, context)

	aboutBatch, err := results[0].Batch()
	check(err, context)
	photoBatch, err := results[1].Batch()
	check(err, context)

	aboutResp := aboutBatch.Result
	photoResp := photoBatch.Result

	SaveAboutUser(&aboutResp, context)
	profilePicture := GetUserPhoto(&photoResp, context)

	imagebytes := addLogo(profilePicture, party, context)
	form, mime := CreateImageForm(imagebytes, context, r.Host)

	url := "https://graph.facebook.com/me/photos" +
		"?access_token=" + access_token +
		"&appsecret_proof=" + session.AppsecretProof()
	//+ "&no_story=true"

	uploadResquest, _ := http.NewRequest("POST", url, &form)
	uploadResquest.Header.Set("Content-Type", mime)
	uploadResp, _ := session.Request(uploadResquest)
	check(err, context)

	var photoID string
	uploadResp.DecodeField("id", &photoID)
	redirectUrl := "https://facebook.com/photo.php?fbid=" + photoID + "&makeprofile=1&prof"
	http.Redirect(w, r, redirectUrl, 303)
}

func SaveAboutUser(aboutResp *fb.Result, context appengine.Context) {
	var log Log
	aboutResp.Decode(&log)

	var ageRange map[string]string
	aboutResp.DecodeField("age_range", &ageRange)
	log.AgeRange = ageRange["min"]

	_, err := datastore.Put(context,
		datastore.NewIncompleteKey(context, "log", nil),
		&log)
	check(err, context)
}

func GetUserPhoto(photoResp *fb.Result, context appengine.Context) *image.Image {
	var dataField fb.Result
	photoResp.DecodeField("data", &dataField)

	var url string
	dataField.DecodeField("url", &url)

	client := urlfetch.Client(context)
	resp, err := client.Get(url)
	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	check(err, context)

	reader := bytes.NewReader(data)
	profilePicture, _, err := image.Decode(reader)
	check(err, context)

	return &profilePicture
}

func CreateImageForm(imageBytes []byte, context appengine.Context, host string) (bytes.Buffer, string) {
	var formBuffer bytes.Buffer
	multiWriter := multipart.NewWriter(&formBuffer)

	imageField, err := multiWriter.CreateFormFile("source", "election.png")
	check(err, context)

	imageBuffer := bytes.NewBuffer(imageBytes)
	_, err = io.Copy(imageField, imageBuffer)
	check(err, context)

	messageField, err := multiWriter.CreateFormField("caption")
	check(err, context)
	_, err = messageField.Write([]byte("Created at http://" + host))
	check(err, context)

	multiWriter.Close()

	return formBuffer, multiWriter.FormDataContentType()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"html/template"
	"log"
	"net/http"
	"reflect"
	"regexp"

	_ "github.com/mattn/go-sqlite3"

	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/microcosm-cc/bluemonday"
	"github.com/mt2d2/forum/model"
	"github.com/russross/blackfriday"
)

func convertToMarkdown(markdown string) template.HTML {
	unsafe := blackfriday.MarkdownCommon([]byte(markdown))

	policy := bluemonday.UGCPolicy()
	policy.AllowElements("video", "audio", "source")
	policy.AllowAttrs("controls").OnElements("video", "audio")
	policy.AllowAttrs("src").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally()

	html := policy.SanitizeBytes(unsafe)
	return template.HTML(html)
}

func isLastElement(x int, list interface{}) bool {
	val := reflect.ValueOf(list)
	if val.Kind() == reflect.Ptr && !val.IsNil() {
		val = val.Elem()
	}

	return x == val.Len()-1
}

type breadCrumb struct{ URL, Title string }

type app struct {
	templates   *template.Template
	db          *sql.DB
	sessions    *sessions.CookieStore
	breadCrumbs []breadCrumb
}

func newApp() *app {
	db, err := sql.Open("sqlite3", *db)
	if err != nil {
		log.Panicln(err)
	}

	funcMap := template.FuncMap{
		"markDown": convertToMarkdown,
		"last":     isLastElement}

	templates, err := template.New("").Funcs(funcMap).ParseFiles(
		"templates/header.html",
		"templates/footer.html",
		"templates/index.html",
		"templates/forum.html",
		"templates/topic.html",
		"templates/addPost.html",
		"templates/addTopic.html",
		"templates/register.html",
		"templates/login.html",
	)

	if err != nil {
		panic(err)
	}

	sessionStore := sessions.NewCookieStore(securecookie.GenerateRandomKey(64), securecookie.GenerateRandomKey(32))

	breadCrumbs := make([]breadCrumb, 0, 1)
	breadCrumbs = append(breadCrumbs, breadCrumb{"/", "Index"})
	return &app{templates, db, sessionStore, breadCrumbs}
}

func (app *app) destroy() {
	app.db.Close()
}

func (app *app) addBreadCrumb(url, title string) {
	app.breadCrumbs = append(app.breadCrumbs, breadCrumb{url, title})
}

func (app *app) useBreadCrumbs() *[]breadCrumb {
	ret := app.breadCrumbs
	app.breadCrumbs = app.breadCrumbs[:1]
	return &ret
}

func (app *app) addErrorFlashes(w http.ResponseWriter, r *http.Request, errs []error) {
	for _, err := range errs {
		app.addErrorFlash(w, r, err)
	}
}

func (app *app) addErrorFlash(w http.ResponseWriter, r *http.Request, error error) {
	app.addFlash(w, r, error.Error(), "error")
}

func (app *app) addSuccessFlash(w http.ResponseWriter, r *http.Request, str string) {
	app.addFlash(w, r, str, "success")
}

func (app *app) addFlash(w http.ResponseWriter, r *http.Request, content interface{}, key string) {
	session, _ := app.sessions.Get(r, "forumSession")
	session.AddFlash(content, key)
	session.Save(r, w)
}

func (app *app) renderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, data map[string]interface{}) {
	session, _ := app.sessions.Get(r, "forumSession")

	data["breadCrumbs"] = app.useBreadCrumbs()
	data["errorFlashes"] = session.Flashes("error")
	data["successFlashes"] = session.Flashes("success")

	if userID, ok := session.Values["user_id"].(int); ok {
		user, err := model.FindOneUserById(app.db, userID)
		if err == nil {
			data["user"] = user
		}
	}

	session.Save(r, w)

	err := app.templates.ExecuteTemplate(w, tmpl+".html", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
<commit_msg>use go.rice<commit_after>package main

import (
	"database/sql"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"reflect"
	"regexp"

	"github.com/GeertJohan/go.rice"
	_ "github.com/mattn/go-sqlite3"

	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/microcosm-cc/bluemonday"
	"github.com/mt2d2/forum/model"
	"github.com/russross/blackfriday"
)

func convertToMarkdown(markdown string) template.HTML {
	unsafe := blackfriday.MarkdownCommon([]byte(markdown))

	policy := bluemonday.UGCPolicy()
	policy.AllowElements("video", "audio", "source")
	policy.AllowAttrs("controls").OnElements("video", "audio")
	policy.AllowAttrs("src").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally()

	html := policy.SanitizeBytes(unsafe)
	return template.HTML(html)
}

func isLastElement(x int, list interface{}) bool {
	val := reflect.ValueOf(list)
	if val.Kind() == reflect.Ptr && !val.IsNil() {
		val = val.Elem()
	}

	return x == val.Len()-1
}

type breadCrumb struct{ URL, Title string }

type app struct {
	templates   *template.Template
	db          *sql.DB
	sessions    *sessions.CookieStore
	breadCrumbs []breadCrumb
}

func embedTemplate(box *rice.Box, tplName string) string {
	tpl, err := box.String(tplName)
	if err != nil {
		return ""
	}
	return fmt.Sprintf("{{define \"%s\"}}%s{{end}}", tplName, tpl)
}

func newApp() *app {
	db, err := sql.Open("sqlite3", *db)
	if err != nil {
		log.Panicln(err)
	}

	funcMap := template.FuncMap{
		"markDown": convertToMarkdown,
		"last":     isLastElement}

	templateBox := rice.MustFindBox("templates")
	templates := template.New("").Funcs(funcMap)
	templates.Parse(embedTemplate(templateBox, "header.html"))
	templates.Parse(embedTemplate(templateBox, "footer.html"))
	templates.Parse(embedTemplate(templateBox, "index.html"))
	templates.Parse(embedTemplate(templateBox, "forum.html"))
	templates.Parse(embedTemplate(templateBox, "topic.html"))
	templates.Parse(embedTemplate(templateBox, "addPost.html"))
	templates.Parse(embedTemplate(templateBox, "addTopic.html"))
	templates.Parse(embedTemplate(templateBox, "register.html"))
	templates.Parse(embedTemplate(templateBox, "login.html"))

	sessionStore := sessions.NewCookieStore(securecookie.GenerateRandomKey(64), securecookie.GenerateRandomKey(32))

	breadCrumbs := make([]breadCrumb, 0, 1)
	breadCrumbs = append(breadCrumbs, breadCrumb{"/", "Index"})
	return &app{templates, db, sessionStore, breadCrumbs}
}

func (app *app) destroy() {
	app.db.Close()
}

func (app *app) addBreadCrumb(url, title string) {
	app.breadCrumbs = append(app.breadCrumbs, breadCrumb{url, title})
}

func (app *app) useBreadCrumbs() *[]breadCrumb {
	ret := app.breadCrumbs
	app.breadCrumbs = app.breadCrumbs[:1]
	return &ret
}

func (app *app) addErrorFlashes(w http.ResponseWriter, r *http.Request, errs []error) {
	for _, err := range errs {
		app.addErrorFlash(w, r, err)
	}
}

func (app *app) addErrorFlash(w http.ResponseWriter, r *http.Request, error error) {
	app.addFlash(w, r, error.Error(), "error")
}

func (app *app) addSuccessFlash(w http.ResponseWriter, r *http.Request, str string) {
	app.addFlash(w, r, str, "success")
}

func (app *app) addFlash(w http.ResponseWriter, r *http.Request, content interface{}, key string) {
	session, _ := app.sessions.Get(r, "forumSession")
	session.AddFlash(content, key)
	session.Save(r, w)
}

func (app *app) renderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, data map[string]interface{}) {
	session, _ := app.sessions.Get(r, "forumSession")

	data["breadCrumbs"] = app.useBreadCrumbs()
	data["errorFlashes"] = session.Flashes("error")
	data["successFlashes"] = session.Flashes("success")

	if userID, ok := session.Values["user_id"].(int); ok {
		user, err := model.FindOneUserById(app.db, userID)
		if err == nil {
			data["user"] = user
		}
	}

	session.Save(r, w)

	w.Header().Set("Content-Type", "text/html")
	err := app.templates.ExecuteTemplate(w, tmpl+".html", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"html/template"
	"os"

	"io/ioutil"

	"reflect"

	"github.com/fatih/color"
	"github.com/olekukonko/tablewriter"
	log "github.com/sirupsen/logrus"
)

type App struct {
	Name            string
	Usage           string
	LongDescription string
	Copyright       string
	ParsingOrder    []ParsingType
	Command         *Command
	Authors         []Author
	HelpCommands    map[string]bool
	Action          func()
	ConfigFlag      string
	RemoveColor     bool
	args            []string
}

type ParsingType int

const (
	EnvironmentVariables ParsingType = iota
	JsonConfig
	YamlConfig
	TomlConfig
	CliFlags
)

var ParingTypeStringMap = map[ParsingType]string{
	EnvironmentVariables: "Environment",
	JsonConfig:           "JSON Config",
	YamlConfig:           "YAML Config",
	TomlConfig:           "Toml Config",
	CliFlags:             "CLI Flag",
}

// Create a new application with default values set.
func NewApp() *App {
	return &App{
		Name:    "cli",
		Authors: make([]Author, 0),
		HelpCommands: map[string]bool{
			"--help": true,
			"-h":     true,
			"help":   true,
		},
		ParsingOrder: []ParsingType{
			EnvironmentVariables,
			JsonConfig,
			YamlConfig,
			TomlConfig,
			CliFlags,
		},
	}
}

// Run the app. Should be called with:
// app := cli.NewApp()
// app.Run(os.Args)
func (a *App) Run(args []string) {
	a.args = args[1:]

	a.checkForConfig()
	a.parseCommands()

	err := a.flagSet.Parse(a.args)
	if err != nil {
		return
	}
}

func (a *App) checkForConfig() {

}

func (a *App) parseCommands() {
	if a.Command == nil {
		log.Fatal("No command attached to the app!")
	}
	a.Command.buildTree(nil)
	a.Command.assignArguments(a.args)

	if helpCommand, isHelp := a.Command.isHelpCommand(a.HelpCommands); isHelp {
		fmt.Println("help.", helpCommand.Name)
		return
	}

	if err := a.Command.parseFlags(); err != nil {
		// TODO: Fix me.
		return
	}

	a.parseByOrder()
}

func (a *App) parseByOrder() error {
	settingsMap := newMappedSettings()

	for _, order := range a.ParsingOrder {
		switch order {
		case EnvironmentVariables:
			settingsMap.addArray(a.Command.parseEnvVars())

		case JsonConfig:

		case YamlConfig:

		case TomlConfig:

		case CliFlags:
			settingsMap.addArray(a.Command.getSetFlags())
		}
	}
	settingsMap.PrintDuplicates(a.Command.GetActiveCommands())
	settingsMap.PrintDuplicatesStdout(a.RemoveColor)
	return nil
}

type mappedSettings struct {
	MainMap map[string]map[string][]activeSetting `json:"main_map"`
}

func newMappedSettings() *mappedSettings {
	return &mappedSettings{
		MainMap: make(map[string]map[string][]activeSetting),
	}
}

func (m *mappedSettings) addArray(settings []activeSetting) {
	for _, setting := range settings {
		if m.MainMap[setting.CommandPath] == nil {
			m.MainMap[setting.CommandPath] = make(map[string][]activeSetting)
		}
		if m.MainMap[setting.CommandPath][setting.VariableName] == nil {
			m.MainMap[setting.CommandPath][setting.VariableName] = make([]activeSetting, 0)
		}
		m.MainMap[setting.CommandPath][setting.VariableName] = append(m.MainMap[setting.CommandPath][setting.VariableName], setting)
	}
}

// Helper to print duplciates in table format to Stdout.
func (m *mappedSettings) PrintDuplicates(commands []*Command) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Command", "Variable", "Source", "Value", "Type", "Status"})
	for _, command := range commands {
		expandedName := command.GetExpandedName()
		if m.MainMap[expandedName] == nil {
			continue
		}
		for _, settings := range m.MainMap[expandedName] {
			length := len(settings)
			for i, setting := range settings {
				var status string
				if i == length-1 {
					status = "✔ Used"
				} else {
					status = "x Ignored"
				}
				row := []string{
					expandedName,
					setting.VariableName,
					ParingTypeStringMap[setting.Source],
					fmt.Sprintf("%s", setting.Value),
					reflect.TypeOf(setting.Value).String(),
					status,
				}
				if setting.Source == EnvironmentVariables {
					row[1] += " (" + convertNameToOS(setting.VariableName) + ")"
				}
				table.Append(row)
			}
		}
	}
	table.Render()
}

// Use a custom formatted string to print duplicates on Stdout.
func (m *mappedSettings) PrintDuplicatesStdout(noColor bool) {
	t := template.New("duplicates")
	funcMap := template.FuncMap{
		"blue":  color.BlueString,
		"red":   color.RedString,
		"green": color.GreenString,
		"bold":  color.New(color.Bold).Sprint,
		"sourceString": func(p ParsingType) string {
			return ParingTypeStringMap[p]
		},
		"plus1": func(x int) int {
			return x + 1
		},
	}
	if noColor {
		funcMap["blue"] = identityString
		funcMap["red"] = identityString
		funcMap["green"] = identityString
		funcMap["bold"] = identityString
	}
	t.Funcs(funcMap)
	t.Parse(`{{ range $command, $variables := . -}}
{{ blue "Configuration:"}} {{ bold $command }}
	{{ range $key, $vars := $variables -}}
	{{ range $k, $var := $vars }}{{ $length := len $vars -}}
		{{ if eq $length (plus1 $k) -}}
			{{ green $key }} = {{ green $var.Value }}
		{{ green "set from" }} {{ sourceString $var.Source -}}
		{{ else -}}
			{{ red $key }} = {{ red $var.Value }}
		{{ red "ignored from" }} {{ sourceString $var.Source -}}
		{{ end }}
	{{ end -}}
	{{ end }}
{{ end }}`)
	t.Execute(os.Stdout, m.MainMap)
}

func identityString(s string) string {
	return s
}
<commit_msg>more unused flags<commit_after>package cli

import (
	"fmt"
	"html/template"
	"os"

	"io/ioutil"

	"reflect"

	"github.com/fatih/color"
	"github.com/olekukonko/tablewriter"
	log "github.com/sirupsen/logrus"
)

type App struct {
	Name            string
	Usage           string
	LongDescription string
	Copyright       string
	ParsingOrder    []ParsingType
	Command         *Command
	Authors         []Author
	HelpCommands    map[string]bool
	Action          func()
	ConfigFlag      string
	RemoveColor     bool
	args            []string
}

type ParsingType int

const (
	EnvironmentVariables ParsingType = iota
	JsonConfig
	YamlConfig
	TomlConfig
	CliFlags
)

var ParingTypeStringMap = map[ParsingType]string{
	EnvironmentVariables: "Environment",
	JsonConfig:           "JSON Config",
	YamlConfig:           "YAML Config",
	TomlConfig:           "Toml Config",
	CliFlags:             "CLI Flag",
}

// Create a new application with default values set.
func NewApp() *App {
	return &App{
		Name:    "cli",
		Authors: make([]Author, 0),
		HelpCommands: map[string]bool{
			"--help": true,
			"-h":     true,
			"help":   true,
		},
		ParsingOrder: []ParsingType{
			EnvironmentVariables,
			JsonConfig,
			YamlConfig,
			TomlConfig,
			CliFlags,
		},
	}
}

// Run the app. Should be called with:
// app := cli.NewApp()
// app.Run(os.Args)
func (a *App) Run(args []string) {
	a.args = args[1:]

	a.checkForConfig()
	a.parseCommands()

}

func (a *App) checkForConfig() {

}

func (a *App) parseCommands() {
	if a.Command == nil {
		log.Fatal("No command attached to the app!")
	}
	a.Command.buildTree(nil)
	a.Command.assignArguments(a.args)

	if helpCommand, isHelp := a.Command.isHelpCommand(a.HelpCommands); isHelp {
		fmt.Println("help.", helpCommand.Name)
		return
	}

	if err := a.Command.parseFlags(); err != nil {
		// TODO: Fix me.
		return
	}

	a.parseByOrder()
}

func (a *App) parseByOrder() error {
	settingsMap := newMappedSettings()

	for _, order := range a.ParsingOrder {
		switch order {
		case EnvironmentVariables:
			settingsMap.addArray(a.Command.parseEnvVars())

		case JsonConfig:

		case YamlConfig:

		case TomlConfig:

		case CliFlags:
			settingsMap.addArray(a.Command.getSetFlags())
		}
	}
	settingsMap.PrintDuplicates(a.Command.GetActiveCommands())
	settingsMap.PrintDuplicatesStdout(a.RemoveColor)
	return nil
}

type mappedSettings struct {
	MainMap map[string]map[string][]activeSetting `json:"main_map"`
}

func newMappedSettings() *mappedSettings {
	return &mappedSettings{
		MainMap: make(map[string]map[string][]activeSetting),
	}
}

func (m *mappedSettings) addArray(settings []activeSetting) {
	for _, setting := range settings {
		if m.MainMap[setting.CommandPath] == nil {
			m.MainMap[setting.CommandPath] = make(map[string][]activeSetting)
		}
		if m.MainMap[setting.CommandPath][setting.VariableName] == nil {
			m.MainMap[setting.CommandPath][setting.VariableName] = make([]activeSetting, 0)
		}
		m.MainMap[setting.CommandPath][setting.VariableName] = append(m.MainMap[setting.CommandPath][setting.VariableName], setting)
	}
}

// Helper to print duplciates in table format to Stdout.
func (m *mappedSettings) PrintDuplicates(commands []*Command) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Command", "Variable", "Source", "Value", "Type", "Status"})
	for _, command := range commands {
		expandedName := command.GetExpandedName()
		if m.MainMap[expandedName] == nil {
			continue
		}
		for _, settings := range m.MainMap[expandedName] {
			length := len(settings)
			for i, setting := range settings {
				var status string
				if i == length-1 {
					status = "✔ Used"
				} else {
					status = "x Ignored"
				}
				row := []string{
					expandedName,
					setting.VariableName,
					ParingTypeStringMap[setting.Source],
					fmt.Sprintf("%s", setting.Value),
					reflect.TypeOf(setting.Value).String(),
					status,
				}
				if setting.Source == EnvironmentVariables {
					row[1] += " (" + convertNameToOS(setting.VariableName) + ")"
				}
				table.Append(row)
			}
		}
	}
	table.Render()
}

// Use a custom formatted string to print duplicates on Stdout.
func (m *mappedSettings) PrintDuplicatesStdout(noColor bool) {
	t := template.New("duplicates")
	funcMap := template.FuncMap{
		"blue":  color.BlueString,
		"red":   color.RedString,
		"green": color.GreenString,
		"bold":  color.New(color.Bold).Sprint,
		"sourceString": func(p ParsingType) string {
			return ParingTypeStringMap[p]
		},
		"plus1": func(x int) int {
			return x + 1
		},
	}
	if noColor {
		funcMap["blue"] = identityString
		funcMap["red"] = identityString
		funcMap["green"] = identityString
		funcMap["bold"] = identityString
	}
	t.Funcs(funcMap)
	t.Parse(`{{ range $command, $variables := . -}}
{{ blue "Configuration:"}} {{ bold $command }}
	{{ range $key, $vars := $variables -}}
	{{ range $k, $var := $vars }}{{ $length := len $vars -}}
		{{ if eq $length (plus1 $k) -}}
			{{ green $key }} = {{ green $var.Value }}
		{{ green "set from" }} {{ sourceString $var.Source -}}
		{{ else -}}
			{{ red $key }} = {{ red $var.Value }}
		{{ red "ignored from" }} {{ sourceString $var.Source -}}
		{{ end }}
	{{ end -}}
	{{ end }}
{{ end }}`)
	t.Execute(os.Stdout, m.MainMap)
}

func identityString(s string) string {
	return s
}
<|endoftext|>


<commit_before>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"testing"
)

// Verified against ST3
func TestRegionIntersects(t *testing.T) {
	type Test struct {
		a, b Region
		c    bool
	}
	var tests = []Test{
		{Region{10, 20}, Region{25, 35}, false},
		{Region{25, 35}, Region{10, 20}, false},
		{Region{10, 25}, Region{20, 35}, true},
		{Region{20, 35}, Region{10, 25}, true},
		{Region{10, 25}, Region{15, 20}, true},
		{Region{15, 20}, Region{10, 25}, true},
		{Region{5, 10}, Region{10, 23}, false},
		{Region{5, 10}, Region{5, 10}, true},
		{Region{0, 0}, Region{0, 0}, true},
		{Region{1, 1}, Region{1, 1}, true},
		{Region{23, 24}, Region{10, 23}, false},
	}
	for _, test := range tests {
		if res := test.a.Intersects(test.b); res != test.c {
			t.Errorf("Expected %v, but got %v, %v", test.c, res, test)
		}
	}
}

// Verified against ST3
func TestRegionIntersection(t *testing.T) {
	var tests = [][]Region{
		{{10, 20}, {25, 35}, {0, 0}},
		{{25, 35}, {10, 20}, {0, 0}},
		{{10, 25}, {20, 35}, {20, 25}},
		{{20, 35}, {10, 25}, {20, 25}},
		{{10, 25}, {15, 20}, {15, 20}},
		{{15, 20}, {10, 25}, {15, 20}},
		{{5, 10}, {10, 23}, {0, 0}},
		{{5, 10}, {5, 10}, {5, 10}},
		{{1, 1}, {1, 1}, {0, 0}},
	}
	for _, test := range tests {
		if res := test[0].Intersection(test[1]); res != test[2] {
			t.Errorf("Expected intersection %v, but got %v, %v", test[2], res, test)
		}
	}
}

func TestClip(t *testing.T) {
	tests := [][]Region{
		{{10, 20}, {25, 35}, {10, 20}},
		{{10, 20}, {0, 5}, {10, 20}},
		{{10, 20}, {0, 11}, {11, 20}},
		{{10, 20}, {0, 15}, {15, 20}},
		{{10, 20}, {15, 30}, {10, 15}},
		{{10, 20}, {20, 30}, {10, 20}},
		{{10, 20}, {0, 30}, {10, 20}},
		{{10, 20}, {10, 20}, {10, 20}},
	}
	for i := range tests {
		a := tests[i][0]
		ignoreRegion := tests[i][1]
		a = a.Clip(ignoreRegion)
		if a != tests[i][2] {
			t.Errorf("Expected %v, got: %v", tests[i][2], a)
		}
	}
}

// Verified against ST3
func TestContains(t *testing.T) {
	type Test struct {
		r   Region
		pos int
		c   bool
	}
	tests := []Test{
		{Region{0, 0}, 0, true},
		{Region{10, 10}, 10, true},
		{Region{10, 11}, 10, true},
		{Region{10, 11}, 11, true},
		{Region{10, 11}, 12, false},
		{Region{10, 11}, 9, false},
	}
	for _, test := range tests {
		if res := test.r.Contains(test.pos); res != test.c {
			t.Errorf("Expected %v, but got %v, %v, %v", test.c, res, test.r, test.pos)
		}
	}
}
<commit_msg>text: Add ST3 verified TestCover<commit_after>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"reflect"
	"testing"
)

// Verified against ST3
func TestRegionIntersects(t *testing.T) {
	type Test struct {
		a, b Region
		c    bool
	}
	var tests = []Test{
		{Region{10, 20}, Region{25, 35}, false},
		{Region{25, 35}, Region{10, 20}, false},
		{Region{10, 25}, Region{20, 35}, true},
		{Region{20, 35}, Region{10, 25}, true},
		{Region{10, 25}, Region{15, 20}, true},
		{Region{15, 20}, Region{10, 25}, true},
		{Region{5, 10}, Region{10, 23}, false},
		{Region{5, 10}, Region{5, 10}, true},
		{Region{0, 0}, Region{0, 0}, true},
		{Region{1, 1}, Region{1, 1}, true},
		{Region{23, 24}, Region{10, 23}, false},
	}
	for _, test := range tests {
		if res := test.a.Intersects(test.b); res != test.c {
			t.Errorf("Expected %v, but got %v, %v", test.c, res, test)
		}
	}
}

// Verified against ST3
func TestRegionIntersection(t *testing.T) {
	var tests = [][]Region{
		{{10, 20}, {25, 35}, {0, 0}},
		{{25, 35}, {10, 20}, {0, 0}},
		{{10, 25}, {20, 35}, {20, 25}},
		{{20, 35}, {10, 25}, {20, 25}},
		{{10, 25}, {15, 20}, {15, 20}},
		{{15, 20}, {10, 25}, {15, 20}},
		{{5, 10}, {10, 23}, {0, 0}},
		{{5, 10}, {5, 10}, {5, 10}},
		{{1, 1}, {1, 1}, {0, 0}},
	}
	for _, test := range tests {
		if res := test[0].Intersection(test[1]); res != test[2] {
			t.Errorf("Expected intersection %v, but got %v, %v", test[2], res, test)
		}
	}
}

func TestClip(t *testing.T) {
	tests := [][]Region{
		{{10, 20}, {25, 35}, {10, 20}},
		{{10, 20}, {0, 5}, {10, 20}},
		{{10, 20}, {0, 11}, {11, 20}},
		{{10, 20}, {0, 15}, {15, 20}},
		{{10, 20}, {15, 30}, {10, 15}},
		{{10, 20}, {20, 30}, {10, 20}},
		{{10, 20}, {0, 30}, {10, 20}},
		{{10, 20}, {10, 20}, {10, 20}},
	}
	for i := range tests {
		a := tests[i][0]
		ignoreRegion := tests[i][1]
		a = a.Clip(ignoreRegion)
		if a != tests[i][2] {
			t.Errorf("Expected %v, got: %v", tests[i][2], a)
		}
	}
}

// Verified against ST3
func TestContains(t *testing.T) {
	type Test struct {
		r   Region
		pos int
		c   bool
	}
	tests := []Test{
		{Region{0, 0}, 0, true},
		{Region{10, 10}, 10, true},
		{Region{10, 11}, 10, true},
		{Region{10, 11}, 11, true},
		{Region{10, 11}, 12, false},
		{Region{10, 11}, 9, false},
	}
	for _, test := range tests {
		if res := test.r.Contains(test.pos); res != test.c {
			t.Errorf("Expected %v, but got %v, %v, %v", test.c, res, test.r, test.pos)
		}
	}
}

// Verified against ST3
func TestCover(t *testing.T) {
	tests := []struct {
		a, b Region
		out  Region
	}{
		{Region{0, 1}, Region{1, 0}, Region{0, 1}},
		{Region{1, 0}, Region{0, 1}, Region{1, 0}},
		{Region{1, 0}, Region{5, 10}, Region{10, 0}},
		{Region{5, 10}, Region{1, 0}, Region{0, 10}},
	}
	for _, test := range tests {
		if res := test.a.Cover(test.b); !reflect.DeepEqual(res, test.out) {
			t.Errorf("Expected %v, but got %v", test.out, res)
		}
	}

}
<|endoftext|>