<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package openstack

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"k8s.io/klog/v2"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	cloudprovider "k8s.io/cloud-provider"
	"k8s.io/cloud-provider-openstack/pkg/cloudprovider/providers/openstack/metrics"
	"k8s.io/cloud-provider-openstack/pkg/util/errors"
	"k8s.io/cloud-provider-openstack/pkg/util/metadata"
)

// Instances encapsulates an implementation of Instances for OpenStack.
type Instances struct {
	compute        *gophercloud.ServiceClient
	opts           MetadataOpts
	networkingOpts NetworkingOpts
}

const (
	instanceShutoff = "SHUTOFF"
)

// Instances returns an implementation of Instances for OpenStack.
func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
	return os.instances()
}

// InstancesV2 returns an implementation of InstancesV2 for OpenStack.
// TODO: Support InstancesV2 in the future.
func (os *OpenStack) InstancesV2() (cloudprovider.InstancesV2, bool) {
	return nil, false
}

func (os *OpenStack) instances() (*Instances, bool) {
	klog.V(4).Info("openstack.Instances() called")

	compute, err := os.NewComputeV2()
	if err != nil {
		klog.Errorf("unable to access compute v2 API : %v", err)
		return nil, false
	}

	return &Instances{
		compute:        compute,
		opts:           os.metadataOpts,
		networkingOpts: os.networkingOpts,
	}, true
}

// CurrentNodeName implements Instances.CurrentNodeName
// Note this is *not* necessarily the same as hostname.
func (i *Instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
	md, err := metadata.Get(i.opts.SearchOrder)
	if err != nil {
		return "", err
	}
	return types.NodeName(md.Name), nil
}

// AddSSHKeyToAllInstances is not implemented for OpenStack
func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
	return cloudprovider.NotImplemented
}

// NodeAddresses implements Instances.NodeAddresses
func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
	klog.V(4).Infof("NodeAddresses(%v) called", name)

	addrs, err := getAddressesByName(i.compute, name, i.networkingOpts)
	if err != nil {
		return nil, err
	}

	klog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs)
	return addrs, nil
}

// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
	klog.V(4).Infof("NodeAddressesByProviderID (%v) called", providerID)

	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()

	if mc.ObserveRequest(err) != nil {
		return []v1.NodeAddress{}, err
	}

	interfaces, err := getAttachedInterfacesByID(i.compute, server.ID)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	addresses, err := nodeAddresses(server, interfaces, i.networkingOpts)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	klog.V(4).Infof("NodeAddressesByProviderID(%v) => %v", providerID, addresses)
	return addresses, nil
}

// InstanceExists returns true if the instance for the given node exists.
func (i *Instances) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) {
	return i.InstanceExistsByProviderID(ctx, node.Spec.ProviderID)
}

// InstanceExistsByProviderID returns true if the instance with the given provider id still exists.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	mc := metrics.NewMetricContext("server", "get")
	_, err = servers.Get(i.compute, instanceID).Extract()
	if mc.ObserveRequest(err) != nil {
		if errors.IsNotFound(err) {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

// InstanceShutdown returns true if the instances is in safe state to detach volumes.
// It is the only state, where volumes can be detached immediately.
func (i *Instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) {
	return i.InstanceShutdownByProviderID(ctx, node.Spec.ProviderID)
}

// InstanceShutdownByProviderID returns true if the instances is in safe state to detach volumes.
// It is the only state, where volumes can be detached immediately.
func (i *Instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()
	if mc.ObserveRequest(err) != nil {
		return false, err
	}

	// SHUTOFF is the only state where we can detach volumes immediately
	if server.Status == instanceShutoff {
		return true, nil
	}
	return false, nil
}

// InstanceMetadata returns metadata of the specified instance.
func (i *Instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
	instanceID, err := instanceIDFromProviderID(node.Spec.ProviderID)
	if err != nil {
		return nil, err
	}

	srv, err := servers.Get(i.compute, instanceID).Extract()
	if err != nil {
		return nil, err
	}

	instanceType, err := srvInstanceType(srv)
	if err != nil {
		return nil, err
	}

	interfaces, err := getAttachedInterfacesByID(i.compute, srv.ID)
	if err != nil {
		return nil, err
	}
	addresses, err := nodeAddresses(srv, interfaces, i.networkingOpts)
	if err != nil {
		return nil, err
	}

	return &cloudprovider.InstanceMetadata{
		ProviderID:    node.Spec.ProviderID,
		InstanceType:  instanceType,
		NodeAddresses: addresses,
	}, nil
}

// InstanceID returns the kubelet's cloud provider ID.
func (os *OpenStack) InstanceID() (string, error) {
	if len(os.localInstanceID) == 0 {
		id, err := readInstanceID(os.metadataOpts.SearchOrder)
		if err != nil {
			return "", err
		}
		os.localInstanceID = id
	}
	return os.localInstanceID, nil
}

// InstanceID returns the cloud provider ID of the specified instance.
func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	// In the future it is possible to also return an endpoint as:
	// <endpoint>/<instanceid>
	return "/" + srv.ID, nil
}

// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return "", err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()

	if mc.ObserveRequest(err) != nil {
		return "", err
	}

	return srvInstanceType(server)
}

// InstanceType returns the type of the specified instance.
func (i *Instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name)

	if err != nil {
		return "", err
	}

	return srvInstanceType(&srv.Server)
}

func srvInstanceType(srv *servers.Server) (string, error) {
	keys := []string{"name", "id", "original_name"}
	for _, key := range keys {
		val, found := srv.Flavor[key]
		if found {
			flavor, ok := val.(string)
			if ok {
				return flavor, nil
			}
		}
	}
	return "", fmt.Errorf("flavor name/id not found")
}

// If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too.
var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`)

// instanceIDFromProviderID splits a provider's id and return instanceID.
// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'.
// See cloudprovider.GetInstanceProviderID and Instances.InstanceID.
func instanceIDFromProviderID(providerID string) (instanceID string, err error) {

	// https://github.com/kubernetes/kubernetes/issues/85731
	if providerID != "" && !strings.Contains(providerID, "://") {
		providerID = ProviderName + "://" + providerID
	}

	matches := providerIDRegexp.FindStringSubmatch(providerID)
	if len(matches) != 2 {
		return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID)
	}
	return matches[1], nil
}

// AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice,
// only if they do not already exist
func AddToNodeAddresses(addresses *[]v1.NodeAddress, addAddresses ...v1.NodeAddress) {
	for _, add := range addAddresses {
		exists := false
		for _, existing := range *addresses {
			if existing.Address == add.Address && existing.Type == add.Type {
				exists = true
				break
			}
		}
		if !exists {
			*addresses = append(*addresses, add)
		}
	}
}

// RemoveFromNodeAddresses removes the NodeAddresses from the passed-by-pointer
// slice if they already exist.
func RemoveFromNodeAddresses(addresses *[]v1.NodeAddress, removeAddresses ...v1.NodeAddress) {
	var indexesToRemove []int
	for _, remove := range removeAddresses {
		for i := len(*addresses) - 1; i >= 0; i-- {
			existing := (*addresses)[i]
			if existing.Address == remove.Address && (existing.Type == remove.Type || remove.Type == "") {
				indexesToRemove = append(indexesToRemove, i)
			}
		}
	}
	for _, i := range indexesToRemove {
		if i < len(*addresses) {
			*addresses = append((*addresses)[:i], (*addresses)[i+1:]...)
		}
	}
}
<commit_msg>[occm] lookup flavor name if only id is provided (#1213)<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package openstack

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"k8s.io/klog/v2"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	cloudprovider "k8s.io/cloud-provider"
	"k8s.io/cloud-provider-openstack/pkg/cloudprovider/providers/openstack/metrics"
	"k8s.io/cloud-provider-openstack/pkg/util/errors"
	"k8s.io/cloud-provider-openstack/pkg/util/metadata"
)

// Instances encapsulates an implementation of Instances for OpenStack.
type Instances struct {
	compute        *gophercloud.ServiceClient
	opts           MetadataOpts
	networkingOpts NetworkingOpts
}

const (
	instanceShutoff = "SHUTOFF"
)

// Instances returns an implementation of Instances for OpenStack.
func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
	return os.instances()
}

// InstancesV2 returns an implementation of InstancesV2 for OpenStack.
// TODO: Support InstancesV2 in the future.
func (os *OpenStack) InstancesV2() (cloudprovider.InstancesV2, bool) {
	return nil, false
}

func (os *OpenStack) instances() (*Instances, bool) {
	klog.V(4).Info("openstack.Instances() called")

	compute, err := os.NewComputeV2()
	if err != nil {
		klog.Errorf("unable to access compute v2 API : %v", err)
		return nil, false
	}

	return &Instances{
		compute:        compute,
		opts:           os.metadataOpts,
		networkingOpts: os.networkingOpts,
	}, true
}

// CurrentNodeName implements Instances.CurrentNodeName
// Note this is *not* necessarily the same as hostname.
func (i *Instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
	md, err := metadata.Get(i.opts.SearchOrder)
	if err != nil {
		return "", err
	}
	return types.NodeName(md.Name), nil
}

// AddSSHKeyToAllInstances is not implemented for OpenStack
func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
	return cloudprovider.NotImplemented
}

// NodeAddresses implements Instances.NodeAddresses
func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
	klog.V(4).Infof("NodeAddresses(%v) called", name)

	addrs, err := getAddressesByName(i.compute, name, i.networkingOpts)
	if err != nil {
		return nil, err
	}

	klog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs)
	return addrs, nil
}

// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
	klog.V(4).Infof("NodeAddressesByProviderID (%v) called", providerID)

	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()

	if mc.ObserveRequest(err) != nil {
		return []v1.NodeAddress{}, err
	}

	interfaces, err := getAttachedInterfacesByID(i.compute, server.ID)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	addresses, err := nodeAddresses(server, interfaces, i.networkingOpts)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	klog.V(4).Infof("NodeAddressesByProviderID(%v) => %v", providerID, addresses)
	return addresses, nil
}

// InstanceExists returns true if the instance for the given node exists.
func (i *Instances) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) {
	return i.InstanceExistsByProviderID(ctx, node.Spec.ProviderID)
}

// InstanceExistsByProviderID returns true if the instance with the given provider id still exists.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	mc := metrics.NewMetricContext("server", "get")
	_, err = servers.Get(i.compute, instanceID).Extract()
	if mc.ObserveRequest(err) != nil {
		if errors.IsNotFound(err) {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

// InstanceShutdown returns true if the instances is in safe state to detach volumes.
// It is the only state, where volumes can be detached immediately.
func (i *Instances) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) {
	return i.InstanceShutdownByProviderID(ctx, node.Spec.ProviderID)
}

// InstanceShutdownByProviderID returns true if the instances is in safe state to detach volumes.
// It is the only state, where volumes can be detached immediately.
func (i *Instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()
	if mc.ObserveRequest(err) != nil {
		return false, err
	}

	// SHUTOFF is the only state where we can detach volumes immediately
	if server.Status == instanceShutoff {
		return true, nil
	}
	return false, nil
}

// InstanceMetadata returns metadata of the specified instance.
func (i *Instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
	instanceID, err := instanceIDFromProviderID(node.Spec.ProviderID)
	if err != nil {
		return nil, err
	}

	srv, err := servers.Get(i.compute, instanceID).Extract()
	if err != nil {
		return nil, err
	}

	instanceType, err := srvInstanceType(i.compute, srv)
	if err != nil {
		return nil, err
	}

	interfaces, err := getAttachedInterfacesByID(i.compute, srv.ID)
	if err != nil {
		return nil, err
	}
	addresses, err := nodeAddresses(srv, interfaces, i.networkingOpts)
	if err != nil {
		return nil, err
	}

	return &cloudprovider.InstanceMetadata{
		ProviderID:    node.Spec.ProviderID,
		InstanceType:  instanceType,
		NodeAddresses: addresses,
	}, nil
}

// InstanceID returns the kubelet's cloud provider ID.
func (os *OpenStack) InstanceID() (string, error) {
	if len(os.localInstanceID) == 0 {
		id, err := readInstanceID(os.metadataOpts.SearchOrder)
		if err != nil {
			return "", err
		}
		os.localInstanceID = id
	}
	return os.localInstanceID, nil
}

// InstanceID returns the cloud provider ID of the specified instance.
func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	// In the future it is possible to also return an endpoint as:
	// <endpoint>/<instanceid>
	return "/" + srv.ID, nil
}

// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return "", err
	}

	mc := metrics.NewMetricContext("server", "get")
	server, err := servers.Get(i.compute, instanceID).Extract()

	if mc.ObserveRequest(err) != nil {
		return "", err
	}

	return srvInstanceType(i.compute, server)
}

// InstanceType returns the type of the specified instance.
func (i *Instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name)

	if err != nil {
		return "", err
	}

	return srvInstanceType(i.compute, &srv.Server)
}

func srvInstanceType(client *gophercloud.ServiceClient, srv *servers.Server) (string, error) {
	keys := []string{"original_name", "id"}
	for _, key := range keys {
		val, found := srv.Flavor[key]
		if found {
			flavor, ok := val.(string)
			if ok {
				if key == "id" {
					mc := metrics.NewMetricContext("flavor", "get")
					f, err := flavors.Get(client, flavor).Extract()
					if mc.ObserveRequest(err) == nil {
						return f.Name, nil
					}
				}
				return flavor, nil
			}
		}
	}
	return "", fmt.Errorf("flavor name/id not found")
}

// If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too.
var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`)

// instanceIDFromProviderID splits a provider's id and return instanceID.
// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'.
// See cloudprovider.GetInstanceProviderID and Instances.InstanceID.
func instanceIDFromProviderID(providerID string) (instanceID string, err error) {

	// https://github.com/kubernetes/kubernetes/issues/85731
	if providerID != "" && !strings.Contains(providerID, "://") {
		providerID = ProviderName + "://" + providerID
	}

	matches := providerIDRegexp.FindStringSubmatch(providerID)
	if len(matches) != 2 {
		return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID)
	}
	return matches[1], nil
}

// AddToNodeAddresses appends the NodeAddresses to the passed-by-pointer slice,
// only if they do not already exist
func AddToNodeAddresses(addresses *[]v1.NodeAddress, addAddresses ...v1.NodeAddress) {
	for _, add := range addAddresses {
		exists := false
		for _, existing := range *addresses {
			if existing.Address == add.Address && existing.Type == add.Type {
				exists = true
				break
			}
		}
		if !exists {
			*addresses = append(*addresses, add)
		}
	}
}

// RemoveFromNodeAddresses removes the NodeAddresses from the passed-by-pointer
// slice if they already exist.
func RemoveFromNodeAddresses(addresses *[]v1.NodeAddress, removeAddresses ...v1.NodeAddress) {
	var indexesToRemove []int
	for _, remove := range removeAddresses {
		for i := len(*addresses) - 1; i >= 0; i-- {
			existing := (*addresses)[i]
			if existing.Address == remove.Address && (existing.Type == remove.Type || remove.Type == "") {
				indexesToRemove = append(indexesToRemove, i)
			}
		}
	}
	for _, i := range indexesToRemove {
		if i < len(*addresses) {
			*addresses = append((*addresses)[:i], (*addresses)[i+1:]...)
		}
	}
}
<|endoftext|>


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

package objectstorage

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strconv"
	"testing"
)

func ExampleGetPartSize() {
	fmt.Println(GetPartSize(5000000000))
	// Output: 5242880
}
func ExampleGetPartSize_second() {
	fmt.Println(GetPartSize(50000000000000000))
	// Output: 5368709120
}

// bucketHandler is an http.Handler that verifies bucket responses and validates incoming requests
type bucketHandler struct {
	resource string
}

func (h bucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.Method == "GET":
		if r.URL.Path == "/" {
			response := []byte("<ListAllMyBucketsResult xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"><Buckets><Bucket><Name>bucket</Name><CreationDate>2015-05-20T23:05:09.230Z</CreationDate></Bucket></Buckets><Owner><ID>minio</ID><DisplayName>minio</DisplayName></Owner></ListAllMyBucketsResult>")
			w.Header().Set("Content-Length", strconv.Itoa(len(response)))
			w.Write(response)
		}
	case r.Method == "POST":
		w.WriteHeader(http.StatusOK)
	case r.Method == "PUT":
		switch {
		case r.URL.Path == h.resource:
			_, ok := r.URL.Query()["acl"]
			if ok {
				if r.Header.Get("x-amz-acl") != "public" {
					w.WriteHeader(http.StatusNotImplemented)
				}
			}
			w.WriteHeader(http.StatusOK)
		default:
			w.WriteHeader(http.StatusBadRequest)
		}
	case r.Method == "HEAD":
		switch {
		case r.URL.Path == h.resource:
			w.WriteHeader(http.StatusOK)
		default:
			w.WriteHeader(http.StatusForbidden)
		}
	case r.Method == "DELETE":
		switch {
		case r.URL.Path != h.resource:
			w.WriteHeader(http.StatusNotFound)
		default:
			h.resource = ""
			w.WriteHeader(http.StatusOK)
		}
	}
}

func TestBucketOperations(t *testing.T) {
	bucket := bucketHandler(bucketHandler{
		resource: "/bucket",
	})
	server := httptest.NewServer(bucket)
	defer server.Close()

	a := New(&Config{Endpoint: server.URL})
	err := a.MakeBucket("bucket", "private", "")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.StatBucket("bucket")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.StatBucket("bucket1")
	if err == nil {
		t.Errorf("Error")
	}
	if err.Error() != "403 Forbidden" {
		t.Errorf("Error")
	}

	err = a.SetBucketACL("bucket", "public")
	if err != nil {
		t.Errorf("Error")
	}

	for b := range a.ListBuckets() {
		if b.Err != nil {
			t.Fatalf(b.Err.Error())
		}
		if b.Data.Name != "bucket" {
			t.Errorf("Error")
		}
	}
	err = a.DeleteBucket("bucket")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.DeleteBucket("bucket1")
	if err == nil {
		t.Fatalf("Error")
	}
	if err.Error() != "404 Not Found" {
		t.Errorf("Error")
	}
}

// objectHandler is an http.Handler that verifies object responses and validates incoming requests
type objectHandler struct {
	resource string
	data     []byte
}

func (h objectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.Method == "PUT":
	case r.Method == "HEAD":
	case r.Method == "POST":
	case r.Method == "GET":
	case r.Method == "DELETE":
	}
}

func TestPartSize(t *testing.T) {
	var maxPartSize uint64 = 1024 * 1024 * 1024 * 5
	partSize := GetPartSize(5000000000000000000)
	if partSize > MinimumPartSize {
		if partSize > maxPartSize {
			t.Fatal("invalid result, cannot be bigger than MaxPartSize 5GB")
		}
	}
	partSize = GetPartSize(50000000000)
	if partSize > MinimumPartSize {
		t.Fatal("invalid result, cannot be bigger than MinimumPartSize 5MB")
	}
}

func TestURLEncoding(t *testing.T) {
	type urlStrings struct {
		name        string
		encodedName string
	}

	want := []urlStrings{
		{
			name:        "bigfile-1._%",
			encodedName: "bigfile-1._%25",
		},
		{
			name:        "本語",
			encodedName: "%E6%9C%AC%E8%AA%9E",
		},
		{
			name:        "本b語.1",
			encodedName: "%E6%9C%ACb%E8%AA%9E.1",
		},
		{
			name:        ">123>3123123",
			encodedName: "%3E123%3E3123123",
		},
	}

	for _, u := range want {
		encodedName, err := urlEncodeName(u.name)
		if err != nil {
			t.Fatalf("Error")
		}
		if u.encodedName != encodedName {
			t.Errorf("Error")
		}
	}
}
<commit_msg>Minor change in ACL value<commit_after>/*
 * Minimal object storage library (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package objectstorage

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strconv"
	"testing"
)

func ExampleGetPartSize() {
	fmt.Println(GetPartSize(5000000000))
	// Output: 5242880
}
func ExampleGetPartSize_second() {
	fmt.Println(GetPartSize(50000000000000000))
	// Output: 5368709120
}

// bucketHandler is an http.Handler that verifies bucket responses and validates incoming requests
type bucketHandler struct {
	resource string
}

func (h bucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.Method == "GET":
		if r.URL.Path == "/" {
			response := []byte("<ListAllMyBucketsResult xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"><Buckets><Bucket><Name>bucket</Name><CreationDate>2015-05-20T23:05:09.230Z</CreationDate></Bucket></Buckets><Owner><ID>minio</ID><DisplayName>minio</DisplayName></Owner></ListAllMyBucketsResult>")
			w.Header().Set("Content-Length", strconv.Itoa(len(response)))
			w.Write(response)
		}
	case r.Method == "POST":
		w.WriteHeader(http.StatusOK)
	case r.Method == "PUT":
		switch {
		case r.URL.Path == h.resource:
			_, ok := r.URL.Query()["acl"]
			if ok {
				if r.Header.Get("x-amz-acl") != "public-read-write" {
					w.WriteHeader(http.StatusNotImplemented)
				}
			}
			w.WriteHeader(http.StatusOK)
		default:
			w.WriteHeader(http.StatusBadRequest)
		}
	case r.Method == "HEAD":
		switch {
		case r.URL.Path == h.resource:
			w.WriteHeader(http.StatusOK)
		default:
			w.WriteHeader(http.StatusForbidden)
		}
	case r.Method == "DELETE":
		switch {
		case r.URL.Path != h.resource:
			w.WriteHeader(http.StatusNotFound)
		default:
			h.resource = ""
			w.WriteHeader(http.StatusOK)
		}
	}
}

func TestBucketOperations(t *testing.T) {
	bucket := bucketHandler(bucketHandler{
		resource: "/bucket",
	})
	server := httptest.NewServer(bucket)
	defer server.Close()

	a := New(&Config{Endpoint: server.URL})
	err := a.MakeBucket("bucket", "private", "")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.StatBucket("bucket")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.StatBucket("bucket1")
	if err == nil {
		t.Errorf("Error")
	}
	if err.Error() != "403 Forbidden" {
		t.Errorf("Error")
	}

	err = a.SetBucketACL("bucket", "public-read-write")
	if err != nil {
		t.Errorf("Error")
	}

	for b := range a.ListBuckets() {
		if b.Err != nil {
			t.Fatalf(b.Err.Error())
		}
		if b.Data.Name != "bucket" {
			t.Errorf("Error")
		}
	}
	err = a.DeleteBucket("bucket")
	if err != nil {
		t.Errorf("Error")
	}

	err = a.DeleteBucket("bucket1")
	if err == nil {
		t.Fatalf("Error")
	}
	if err.Error() != "404 Not Found" {
		t.Errorf("Error")
	}
}

// objectHandler is an http.Handler that verifies object responses and validates incoming requests
type objectHandler struct {
	resource string
	data     []byte
}

func (h objectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch {
	case r.Method == "PUT":
	case r.Method == "HEAD":
	case r.Method == "POST":
	case r.Method == "GET":
	case r.Method == "DELETE":
	}
}

func TestPartSize(t *testing.T) {
	var maxPartSize uint64 = 1024 * 1024 * 1024 * 5
	partSize := GetPartSize(5000000000000000000)
	if partSize > MinimumPartSize {
		if partSize > maxPartSize {
			t.Fatal("invalid result, cannot be bigger than MaxPartSize 5GB")
		}
	}
	partSize = GetPartSize(50000000000)
	if partSize > MinimumPartSize {
		t.Fatal("invalid result, cannot be bigger than MinimumPartSize 5MB")
	}
}

func TestURLEncoding(t *testing.T) {
	type urlStrings struct {
		name        string
		encodedName string
	}

	want := []urlStrings{
		{
			name:        "bigfile-1._%",
			encodedName: "bigfile-1._%25",
		},
		{
			name:        "本語",
			encodedName: "%E6%9C%AC%E8%AA%9E",
		},
		{
			name:        "本b語.1",
			encodedName: "%E6%9C%ACb%E8%AA%9E.1",
		},
		{
			name:        ">123>3123123",
			encodedName: "%3E123%3E3123123",
		},
	}

	for _, u := range want {
		encodedName, err := urlEncodeName(u.name)
		if err != nil {
			t.Fatalf("Error")
		}
		if u.encodedName != encodedName {
			t.Errorf("Error")
		}
	}
}
<|endoftext|>


<commit_before>package dcmnet

import (
	"bytes"
	"github.com/jeremyhuiskamp/dcm/dcm"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"testing"
)

func TestParseAssocRQCEcho(t *testing.T) {
	RegisterTestingT(t)

	assocrq := readAssocRQAC("testdata/assocrq_cecho.bin", PDUAssociateRQ)

	Expect(assocrq.ProtocolVersion).To(Equal(int16(1)))
	Expect(assocrq.CalledAE).To(Equal("RIALTO"))
	Expect(assocrq.CallingAE).To(Equal("DCMECHO"))
	Expect(assocrq.ApplicationContext).To(Equal("1.2.840.10008.3.1.1.1"))

	Expect(assocrq.PresentationContexts).To(HaveLen(1))
	pc1 := assocrq.PresentationContexts[0]
	Expect(pc1.ID).To(Equal(PCID(1)))
	Expect(pc1.AbstractSyntax).To(Equal("1.2.840.10008.1.1"))
	Expect(pc1.Result).To(Equal(PCAcceptance)) // should always be 0 in a request
	Expect(pc1.TransferSyntaxes).To(HaveLen(1))
	Expect(pc1.TransferSyntaxes[0]).To(Equal(dcm.ImplicitVRLittleEndian))

	Expect(assocrq.MaxPDULength).To(Equal(uint32(16384)))
	Expect(assocrq.ImplementationClassUID).To(Equal("1.2.40.0.13.1.1"))

	// hmm, not a good test, since these are the defaults:
	Expect(assocrq.MaxOperationsInvoked).To(Equal(uint16(0)))
	Expect(assocrq.MaxOperationsPerformed).To(Equal(uint16(0)))

	Expect(assocrq.ImplementationVersion).To(Equal("dcm4che-2.0"))
}

func TestParseAssocACCEcho(t *testing.T) {
	RegisterTestingT(t)

	assocac := readAssocRQAC("testdata/assocac_cecho.bin", PDUAssociateAC)

	Expect(assocac.ProtocolVersion).To(Equal(int16(1)))
	Expect(assocac.CalledAE).To(Equal("RIALTO"))
	Expect(assocac.CallingAE).To(Equal("DCMECHO"))
	Expect(assocac.ApplicationContext).To(Equal("1.2.840.10008.3.1.1.1"))

	Expect(assocac.PresentationContexts).To(HaveLen(1))
	pc1 := assocac.PresentationContexts[0]
	Expect(pc1.ID).To(Equal(PCID(1)))
	Expect(pc1.AbstractSyntax).To(HaveLen(0))
	Expect(pc1.Result).To(Equal(PCAcceptance))
	Expect(pc1.TransferSyntaxes).To(HaveLen(1))
	Expect(pc1.TransferSyntaxes[0]).To(Equal(dcm.ImplicitVRLittleEndian))

	Expect(assocac.MaxPDULength).To(Equal(uint32(16384)))
	Expect(assocac.ImplementationClassUID).To(Equal("1.2.40.0.13.1.1"))

	// hmm, not a good test, since these are the defaults:
	Expect(assocac.MaxOperationsInvoked).To(Equal(uint16(0)))
	Expect(assocac.MaxOperationsPerformed).To(Equal(uint16(0)))

	Expect(assocac.ImplementationVersion).To(Equal("dcm4che-2.0"))
}

func readAssocRQAC(file string, pduType PDUType) AssociateRQAC {
	b, err := ioutil.ReadFile(file)
	Expect(err).To(BeNil())

	var buf bytes.Buffer
	buf.Write(b)
	buf.WriteString("don't read me bro")

	pduDecoder := NewPDUDecoder(&buf)
	pdu, err := pduDecoder.NextPDU()
	Expect(err).To(BeNil())
	Expect(pdu).ToNot(BeNil())

	Expect(pdu.Type).To(Equal(pduType))
	var rqac AssociateRQAC
	rqac.Read(pdu.Data)

	// ensure that we stopped at the right spot:
	Expect(buf.String()).To(Equal("don't read me bro"))

	return rqac
}
<commit_msg>remove gomega<commit_after>package dcmnet

import (
	"bytes"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/jeremyhuiskamp/dcm/dcm"
)

func TestParseAssocRQCEcho(t *testing.T) {
	exp := AssociateRQAC{
		ProtocolVersion:    1,
		CalledAE:           "RIALTO",
		CallingAE:          "DCMECHO",
		ApplicationContext: "1.2.840.10008.3.1.1.1",
		PresentationContexts: []PresentationContext{{
			ID:             PCID(1),
			Result:         PCAcceptance,
			AbstractSyntax: "1.2.840.10008.1.1",
			TransferSyntaxes: []dcm.TransferSyntax{
				dcm.ImplicitVRLittleEndian,
			},
		}},
		MaxPDULength:           16384,
		ImplementationClassUID: "1.2.40.0.13.1.1",
		ImplementationVersion:  "dcm4che-2.0",
		// hmm, not a good test, since these are the defaults:
		MaxOperationsInvoked:   0,
		MaxOperationsPerformed: 0,
	}
	got := readAssocRQAC(t, "testdata/assocrq_cecho.bin", PDUAssociateRQ)

	if !reflect.DeepEqual(exp, got) {
		t.Fatalf("expected\n%+V\ngot\n%+V", exp, got)
	}
}

func TestParseAssocACCEcho(t *testing.T) {
	exp := AssociateRQAC{
		ProtocolVersion:    1,
		CalledAE:           "RIALTO",
		CallingAE:          "DCMECHO",
		ApplicationContext: "1.2.840.10008.3.1.1.1",
		PresentationContexts: []PresentationContext{{
			ID:             1,
			Result:         PCAcceptance,
			AbstractSyntax: "",
			TransferSyntaxes: []dcm.TransferSyntax{
				dcm.ImplicitVRLittleEndian,
			},
		}},
		MaxPDULength:           16384,
		ImplementationClassUID: "1.2.40.0.13.1.1",
		ImplementationVersion:  "dcm4che-2.0",
		// hmm, not a good test, since these are the defaults:
		MaxOperationsInvoked:   0,
		MaxOperationsPerformed: 0,
	}
	got := readAssocRQAC(t, "testdata/assocac_cecho.bin", PDUAssociateAC)

	if !reflect.DeepEqual(exp, got) {
		t.Fatalf("expected\n%+V\ngot\n%+V", exp, got)
	}
}

func readAssocRQAC(t *testing.T, file string, pduType PDUType) AssociateRQAC {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		t.Fatal(err)
	}

	var buf bytes.Buffer
	buf.Write(b)
	buf.WriteString("don't read me bro")

	pduDecoder := NewPDUDecoder(&buf)
	pdu, err := pduDecoder.NextPDU()
	if err != nil {
		t.Fatal(err)
	}
	if pdu == nil {
		t.Fatal("no pdu found")
	}

	if pduType != pdu.Type {
		t.Fatalf("unexpected pdu type, expected %s, got %s",
			pduType, pdu.Type)
	}
	var rqac AssociateRQAC
	rqac.Read(pdu.Data)

	if "don't read me bro" != buf.String() {
		t.Fatal("didn't stop reading at the right place")
	}

	return rqac
}
<|endoftext|>


<commit_before>//go:generate statik -src=./static

package main

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"

	_ "github.com/jakdept/sp9k1/statik"
)

// SplitHandler allows the routing of one handler at /, and another at all locations below /.
func SplitHandler(root, more http.Handler) http.Handler {
	return splitHandler{bare: root, more: more}
}

type splitHandler struct {
	bare http.Handler
	more http.Handler
}

func (p splitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if path.Clean(r.URL.Path) == "/" {
		p.bare.ServeHTTP(w, r)
	} else {
		p.more.ServeHTTP(w, r)
	}
}

// InternalHandler serves a static, in memory filesystem..
func InternalHandler(fs http.FileSystem) http.Handler {
	return internalHandler{handler: http.FileServer(fs)}
}

type internalHandler struct {
	handler http.Handler
}

func (c internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if path.Ext(r.URL.Path) == ".template" {
		http.Error(w, fmt.Sprintf("template requested, blocked: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - error responding: %s", r.URL.Path)
		return
	}

	c.handler.ServeHTTP(w, r)
	return
}

// IndexHandler lists all files in a directory, and passes them to template execution to build a directory listing.
func IndexHandler(basePath string, templ *template.Template) http.Handler {
	return indexHandler{basePath, templ}
}

type IndexData struct {
	Files []string
	Dirs  []string
	All   []string
}

type indexHandler struct {
	basePath string
	templ    *template.Template
}

func (c indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	f, err := os.Open(filepath.Join(c.basePath, r.URL.Path))
	if err != nil {
		http.Error(w, fmt.Sprintf("not found: %s", r.URL.Path), http.StatusNotFound)
		log.Printf("404 - could not find file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	stat, err := f.Stat()
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read target: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	if !stat.IsDir() {
		http.Error(w, fmt.Sprintf("cannot read target: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	contents, err := f.Readdir(0)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read directory: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - could not read file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	var data IndexData

	for _, each := range contents {
		data.All = append(data.All, each.Name())
		switch each.IsDir() {
		case true:
			data.Dirs = append(data.Dirs, each.Name())
		default:
			data.Files = append(data.Files, each.Name())
		}
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	err = c.templ.Execute(w, data)
	if err != nil {
		http.Error(w, fmt.Sprintf("error building response: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - error responding: %s", err)
		return
	}
}

// ContentTypeHandler serves a given file back to the requester, and determines content type by algorithm only.
// It does not use the file's extension to determine the content type.
func ContentTypeHandler(basePath string) http.Handler {
	return contentTypeHandler{basePath}
}

type contentTypeHandler struct {
	basePath string
}

// contentTypeHandler.ServeHTTP satasifies the Handler interface.
func (c contentTypeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	f, err := os.Open(filepath.Join(c.basePath, r.URL.Path))
	if err != nil {
		http.Error(w, fmt.Sprintf("not found: %s", r.URL.Path), http.StatusNotFound)
		log.Printf("404 - could not open file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	stat, err := f.Stat()
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	chunk := make([]byte, 512)

	_, err = f.Read(chunk)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not read from file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	_, err = f.Seek(0, io.SeekStart)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not seek within file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	w.Header().Set("Content-Type", http.DetectContentType(chunk))
	http.ServeContent(w, r, r.URL.Path, stat.ModTime(), f)

	return
}
<commit_msg>written initial write of thumbnail generation functions<commit_after>//go:generate statik -src=./static

package main

import (
	"fmt"
	"html/template"
	"image"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"

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

	"image/jpeg"
	"image/png"

	_ "github.com/jakdept/sp9k1/statik"
	"github.com/nfnt/resize"
	"github.com/oliamb/cutter"
)

// SplitHandler allows the routing of one handler at /, and another at all locations below /.
func SplitHandler(root, more http.Handler) http.Handler {
	return splitHandler{bare: root, more: more}
}

type splitHandler struct {
	bare http.Handler
	more http.Handler
}

func (p splitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if path.Clean(r.URL.Path) == "/" {
		p.bare.ServeHTTP(w, r)
	} else {
		p.more.ServeHTTP(w, r)
	}
}

// InternalHandler serves a static, in memory filesystem..
func InternalHandler(fs http.FileSystem) http.Handler {
	return internalHandler{handler: http.FileServer(fs)}
}

type internalHandler struct {
	handler http.Handler
}

func (c internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if path.Ext(r.URL.Path) == ".template" {
		http.Error(w, fmt.Sprintf("template requested, blocked: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - error responding: %s", r.URL.Path)
		return
	}

	c.handler.ServeHTTP(w, r)
	return
}

// IndexHandler lists all files in a directory, and passes them to template execution to build a directory listing.
func IndexHandler(basePath string, templ *template.Template) http.Handler {
	return indexHandler{basePath, templ}
}

type IndexData struct {
	Files []string
	Dirs  []string
	All   []string
}

type indexHandler struct {
	basePath string
	templ    *template.Template
}

func (c indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	f, err := os.Open(filepath.Join(c.basePath, r.URL.Path))
	if err != nil {
		http.Error(w, fmt.Sprintf("not found: %s", r.URL.Path), http.StatusNotFound)
		log.Printf("404 - could not find file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	stat, err := f.Stat()
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read target: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	if !stat.IsDir() {
		http.Error(w, fmt.Sprintf("cannot read target: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	contents, err := f.Readdir(0)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read directory: %s", r.URL.Path), http.StatusForbidden)
		log.Printf("403 - could not read file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	var data IndexData

	for _, each := range contents {
		data.All = append(data.All, each.Name())
		switch each.IsDir() {
		case true:
			data.Dirs = append(data.Dirs, each.Name())
		default:
			data.Files = append(data.Files, each.Name())
		}
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	err = c.templ.Execute(w, data)
	if err != nil {
		http.Error(w, fmt.Sprintf("error building response: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - error responding: %s", err)
		return
	}
}

// ContentTypeHandler serves a given file back to the requester, and determines content type by algorithm only.
// It does not use the file's extension to determine the content type.
func ContentTypeHandler(basePath string) http.Handler {
	return contentTypeHandler{basePath}
}

type contentTypeHandler struct {
	basePath string
}

// contentTypeHandler.ServeHTTP satasifies the Handler interface.
func (c contentTypeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	f, err := os.Open(filepath.Join(c.basePath, r.URL.Path))
	if err != nil {
		http.Error(w, fmt.Sprintf("not found: %s", r.URL.Path), http.StatusNotFound)
		log.Printf("404 - could not open file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not stat file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	chunk := make([]byte, 512)

	_, err = f.Read(chunk)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not read from file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	_, err = f.Seek(0, io.SeekStart)
	if err != nil {
		http.Error(w, fmt.Sprintf("cannot read file: %s", r.URL.Path), http.StatusInternalServerError)
		log.Printf("500 - could not seek within file: %s - %s", filepath.Join(c.basePath, r.URL.Path), err)
		return
	}

	w.Header().Set("Content-Type", http.DetectContentType(chunk))
	http.ServeContent(w, r, r.URL.Path, stat.ModTime(), f)

	return
}

func ThumbnailHandler(targetHeight, targetWidth int, rawImageDirectory, thumbnailDirectory string) http.Handler {
	return thumbnailHandler{x: targetHeight, y: targetWidth, raw: rawImageDirectory, thumbs: thumbnailDirectory}
}

type thumbnailHandler struct {
	x        int
	y        int
	raw      string
	thumbs   string
	thumbExt string
}

func (h *thumbnailHandler) openThumb(imageName string) (image.Image, error) {
	img, format, err := h.openImage(fmt.Sprintf("%s/%s.%s", h.thumbs, imageName, h.thumbExt))
	if os.ISNotExist(err) || format != h.thumbExt {
		img, _, err = h.openImage(fmt.Sprintf("%s/%s", h.thumbs, imageName))
		if err != nil {
			return nil, fmt.Errorf("could not open image [%s]: %s", imageName, err)
		}
		img, err = h.generateTHumbnail(img)
		if err != nil {
			return nil, fmt.Errorf("could not process [%s]: %s", imageName, err)
		}
		err = h.writeThumbnail(imageName, img)
		if err != nil {
			return nil, fmt.Errorf("could not cache [%s]: %s", imageName, err)
		}
	}
	if err != nil {
		return nil, fmt.Errorf("problem loading thumbnail [%s]: %s", imageName, err)
	}
	return img, nil
}

func (h *thumbnailHandler) openImage(imageName string) (image.Image, string, error) {
	path := filepath.Clean(imageName)
	reader, err := os.Open(path)
	if err != nil {
		return nil, "", err
	}
	img, format, err := image.Decode(reader)
	if err != nil {
		return nil, "", err
	}
	return img, format, nil
}

func (h *thumbnailHandler) writeThumbnail(imageName string, thumbnailImage image.Image) error {
	out, err := os.Create(filepath.Join(h.raw, imageName))
	if err != nil {
		return err
	}
	defer out.Close()
	switch h.thumbExt {
	case "jpg":
		return jpeg.Encode(out, thumbnailImage, nil)
	case "jpeg":
		return jpeg.Encode(out, thumbnailImage, nil)
	case "png":
		return png.Encode(out, thumbnailImage)
	default:
		return fmt.Errorf("extension type [%s] not supported for thumbnails", h.thumbExt)
	}
}

func (h *thumbnailHandler) generateThumbnail(rawImage image.Image) (image.Image, error) {
	shrunk := resize.Resize(0, uint(h.y), rawImage, resize.MitchellNetravali)
	thumbnail, err := cutter.Crop(shrunk, cutter.Config{
		Height:  h.x,
		Options: cutter.Copy,
		Mode:    cutter.Centered,
	})
	if err != nil {
		return nil, err
	}
	return thumbnail, nil
}
<|endoftext|>


<commit_before>package handler

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/graphql-go/graphql"

	"context"
)

const (
	ContentTypeJSON           = "application/json"
	ContentTypeGraphQL        = "application/graphql"
	ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
)

type Handler struct {
	Schema *graphql.Schema

	pretty bool
}
type RequestOptions struct {
	Query         string                 `json:"query" url:"query" schema:"query"`
	Variables     map[string]interface{} `json:"variables" url:"variables" schema:"variables"`
	OperationName string                 `json:"operationName" url:"operationName" schema:"operationName"`
}

// a workaround for getting`variables` as a JSON string
type requestOptionsCompatibility struct {
	Query         string `json:"query" url:"query" schema:"query"`
	Variables     string `json:"variables" url:"variables" schema:"variables"`
	OperationName string `json:"operationName" url:"operationName" schema:"operationName"`
}

func getFromForm(values url.Values) *RequestOptions {
	query := values.Get("query")
	if query != "" {
		// get variables map
		var variables map[string]interface{}
		variablesStr := values.Get("variables")
		json.Unmarshal([]byte(variablesStr), variables)

		return &RequestOptions{
			Query:         query,
			Variables:     variables,
			OperationName: values.Get("operationName"),
		}
	}

	return nil
}

// RequestOptions Parses a http.Request into GraphQL request options struct
func NewRequestOptions(r *http.Request) *RequestOptions {
	if reqOpt := getFromForm(r.URL.Query()); reqOpt != nil {
		return reqOpt
	}

	if r.Method != "POST" {
		return &RequestOptions{}
	}

	if r.Body == nil {
		return &RequestOptions{}
	}

	// TODO: improve Content-Type handling
	contentTypeStr := r.Header.Get("Content-Type")
	contentTypeTokens := strings.Split(contentTypeStr, ";")
	contentType := contentTypeTokens[0]

	switch contentType {
	case ContentTypeGraphQL:
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return &RequestOptions{}
		}
		return &RequestOptions{
			Query: string(body),
		}
	case ContentTypeFormURLEncoded:
		if err := r.ParseForm(); err != nil {
			return &RequestOptions{}
		}

		if reqOpt := getFromForm(r.PostForm); reqOpt != nil {
			return reqOpt
		}

		return &RequestOptions{}

	case ContentTypeJSON:
		fallthrough
	default:
		var opts RequestOptions
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return &opts
		}
		err = json.Unmarshal(body, &opts)
		if err != nil {
			// Probably `variables` was sent as a string instead of an object.
			// So, we try to be polite and try to parse that as a JSON string
			var optsCompatible requestOptionsCompatibility
			json.Unmarshal(body, &optsCompatible)
			json.Unmarshal([]byte(optsCompatible.Variables), &opts.Variables)
		}
		return &opts
	}
}

// ContextHandler provides an entrypoint into executing graphQL queries with a
// user-provided context.
func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// get query
	opts := NewRequestOptions(r)

	// execute graphql query
	params := graphql.Params{
		Schema:         *h.Schema,
		RequestString:  opts.Query,
		VariableValues: opts.Variables,
		OperationName:  opts.OperationName,
		Context:        ctx,
	}
	result := graphql.Do(params)

	if h.pretty {
		w.WriteHeader(http.StatusOK)
		buff, _ := json.MarshalIndent(result, "", "\t")

		w.Write(buff)
	} else {
		w.WriteHeader(http.StatusOK)
		buff, _ := json.Marshal(result)

		w.Write(buff)
	}
}

// ServeHTTP provides an entrypoint into executing graphQL queries.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.ContextHandler(context.Background(), w, r)
}

type Config struct {
	Schema *graphql.Schema
	Pretty bool
}

func NewConfig() *Config {
	return &Config{
		Schema: nil,
		Pretty: true,
	}
}

func New(p *Config) *Handler {
	if p == nil {
		p = NewConfig()
	}
	if p.Schema == nil {
		panic("undefined GraphQL schema")
	}

	return &Handler{
		Schema: p.Schema,
		pretty: p.Pretty,
	}
}
<commit_msg>use context from http request<commit_after>package handler

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/graphql-go/graphql"

	"context"
)

const (
	ContentTypeJSON           = "application/json"
	ContentTypeGraphQL        = "application/graphql"
	ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
)

type Handler struct {
	Schema *graphql.Schema

	pretty bool
}
type RequestOptions struct {
	Query         string                 `json:"query" url:"query" schema:"query"`
	Variables     map[string]interface{} `json:"variables" url:"variables" schema:"variables"`
	OperationName string                 `json:"operationName" url:"operationName" schema:"operationName"`
}

// a workaround for getting`variables` as a JSON string
type requestOptionsCompatibility struct {
	Query         string `json:"query" url:"query" schema:"query"`
	Variables     string `json:"variables" url:"variables" schema:"variables"`
	OperationName string `json:"operationName" url:"operationName" schema:"operationName"`
}

func getFromForm(values url.Values) *RequestOptions {
	query := values.Get("query")
	if query != "" {
		// get variables map
		var variables map[string]interface{}
		variablesStr := values.Get("variables")
		json.Unmarshal([]byte(variablesStr), variables)

		return &RequestOptions{
			Query:         query,
			Variables:     variables,
			OperationName: values.Get("operationName"),
		}
	}

	return nil
}

// RequestOptions Parses a http.Request into GraphQL request options struct
func NewRequestOptions(r *http.Request) *RequestOptions {
	if reqOpt := getFromForm(r.URL.Query()); reqOpt != nil {
		return reqOpt
	}

	if r.Method != "POST" {
		return &RequestOptions{}
	}

	if r.Body == nil {
		return &RequestOptions{}
	}

	// TODO: improve Content-Type handling
	contentTypeStr := r.Header.Get("Content-Type")
	contentTypeTokens := strings.Split(contentTypeStr, ";")
	contentType := contentTypeTokens[0]

	switch contentType {
	case ContentTypeGraphQL:
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return &RequestOptions{}
		}
		return &RequestOptions{
			Query: string(body),
		}
	case ContentTypeFormURLEncoded:
		if err := r.ParseForm(); err != nil {
			return &RequestOptions{}
		}

		if reqOpt := getFromForm(r.PostForm); reqOpt != nil {
			return reqOpt
		}

		return &RequestOptions{}

	case ContentTypeJSON:
		fallthrough
	default:
		var opts RequestOptions
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return &opts
		}
		err = json.Unmarshal(body, &opts)
		if err != nil {
			// Probably `variables` was sent as a string instead of an object.
			// So, we try to be polite and try to parse that as a JSON string
			var optsCompatible requestOptionsCompatibility
			json.Unmarshal(body, &optsCompatible)
			json.Unmarshal([]byte(optsCompatible.Variables), &opts.Variables)
		}
		return &opts
	}
}

// ContextHandler provides an entrypoint into executing graphQL queries with a
// user-provided context.
func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// get query
	opts := NewRequestOptions(r)

	// execute graphql query
	params := graphql.Params{
		Schema:         *h.Schema,
		RequestString:  opts.Query,
		VariableValues: opts.Variables,
		OperationName:  opts.OperationName,
		Context:        ctx,
	}
	result := graphql.Do(params)

	if h.pretty {
		w.WriteHeader(http.StatusOK)
		buff, _ := json.MarshalIndent(result, "", "\t")

		w.Write(buff)
	} else {
		w.WriteHeader(http.StatusOK)
		buff, _ := json.Marshal(result)

		w.Write(buff)
	}
}

// ServeHTTP provides an entrypoint into executing graphQL queries.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.ContextHandler(r.Context(), w, r)
}

type Config struct {
	Schema *graphql.Schema
	Pretty bool
}

func NewConfig() *Config {
	return &Config{
		Schema: nil,
		Pretty: true,
	}
}

func New(p *Config) *Handler {
	if p == nil {
		p = NewConfig()
	}
	if p.Schema == nil {
		panic("undefined GraphQL schema")
	}

	return &Handler{
		Schema: p.Schema,
		pretty: p.Pretty,
	}
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"log"
	"time"

	"github.com/volatile/core"
	"github.com/volatile/core/coreutil"
	"github.com/whitedevops/colors"
)

// Use tells the core to use this handler.
func Use() {
	core.Use(func(c *core.Context) {
		start := time.Now()
		path := c.Request.URL.Path // Keep original request path in case of http.StripPrefix.

		c.Next()

		log.Printf(colors.ResetAll+"  %s   %s   %s  %s", fmtDuration(start), fmtStatus(c), fmtMethod(c), fmtPath(path))
	})
}

func fmtDuration(start time.Time) string {
	return fmt.Sprintf("%s%s%13s%s", colors.ResetAll, colors.ResetAll+colors.Dim, time.Since(start), colors.ResetAll)
}

func fmtStatus(c *core.Context) string {
	code := coreutil.ResponseStatus(c)

	color := colors.White

	switch {
	case code >= 200 && code <= 299:
		color += colors.BackgroundGreen
	case code >= 300 && code <= 399:
		color += colors.BackgroundCyan
	case code >= 400 && code <= 499:
		color += colors.BackgroundYellow
	default:
		color += colors.BackgroundRed
	}

	return fmt.Sprintf("%s%s %3d %s", colors.ResetAll, color, code, colors.ResetAll)
}

func fmtMethod(c *core.Context) string {
	var color string

	switch c.Request.Method {
	case "GET":
		color += colors.Green
	case "POST":
		color += colors.Cyan
	case "PUT", "PATCH":
		color += colors.Blue
	case "DELETE":
		color += colors.Red
	}

	return fmt.Sprintf("%s%s%s%s", colors.ResetAll, color, c.Request.Method, colors.ResetAll)
}

func fmtPath(path string) string {
	return fmt.Sprintf("%s%s%s%s", colors.ResetAll, colors.Dim, path, colors.ResetAll)
}
<commit_msg>Back to ResponseWriter params<commit_after>package log

import (
	"fmt"
	"log"
	"time"

	"github.com/volatile/core"
	"github.com/volatile/core/coreutil"
	"github.com/whitedevops/colors"
)

// Use tells the core to use this handler.
func Use() {
	core.Use(func(c *core.Context) {
		start := time.Now()
		path := c.Request.URL.Path // Keep original request path in case of http.StripPrefix.

		c.Next()

		log.Printf(colors.ResetAll+"  %s   %s   %s  %s", fmtDuration(start), fmtStatus(c), fmtMethod(c), fmtPath(path))
	})
}

func fmtDuration(start time.Time) string {
	return fmt.Sprintf("%s%s%13s%s", colors.ResetAll, colors.ResetAll+colors.Dim, time.Since(start), colors.ResetAll)
}

func fmtStatus(c *core.Context) string {
	code := coreutil.ResponseStatus(c.ResponseWriter)

	color := colors.White

	switch {
	case code >= 200 && code <= 299:
		color += colors.BackgroundGreen
	case code >= 300 && code <= 399:
		color += colors.BackgroundCyan
	case code >= 400 && code <= 499:
		color += colors.BackgroundYellow
	default:
		color += colors.BackgroundRed
	}

	return fmt.Sprintf("%s%s %3d %s", colors.ResetAll, color, code, colors.ResetAll)
}

func fmtMethod(c *core.Context) string {
	var color string

	switch c.Request.Method {
	case "GET":
		color += colors.Green
	case "POST":
		color += colors.Cyan
	case "PUT", "PATCH":
		color += colors.Blue
	case "DELETE":
		color += colors.Red
	}

	return fmt.Sprintf("%s%s%s%s", colors.ResetAll, color, c.Request.Method, colors.ResetAll)
}

func fmtPath(path string) string {
	return fmt.Sprintf("%s%s%s%s", colors.ResetAll, colors.Dim, path, colors.ResetAll)
}
<|endoftext|>


<commit_before>package siesta

import (
	"errors"
	"net/http"
)

var ErrUnsupportedHandler = errors.New("siesta: unsupported handler")

// ContextHandler is a siesta handler.
type ContextHandler func(Context, http.ResponseWriter, *http.Request, func())

func (h ContextHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(EmptyContext{}, w, r, nil)
}

func (h ContextHandler) ServeHTTPInContext(c Context, w http.ResponseWriter, r *http.Request) {
	h(c, w, r, nil)
}

// ToContextHandler transforms f into a ContextHandler.
// f must be a function with one of the following signatures:
//     func(http.ResponseWriter, *http.Request)
//     func(http.ResponseWriter, *http.Request, func())
//     func(Context, http.ResponseWriter, *http.Request)
//     func(Context, http.ResponseWriter, *http.Request, func())
func ToContextHandler(f interface{}) ContextHandler {
	switch f.(type) {
	case func(Context, http.ResponseWriter, *http.Request, func()):
		return ContextHandler(f.(func(Context, http.ResponseWriter, *http.Request, func())))
	case ContextHandler:
		return f.(ContextHandler)
	case func(Context, http.ResponseWriter, *http.Request):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			f.(func(Context, http.ResponseWriter, *http.Request))(c, w, r)
		}
	case func(http.ResponseWriter, *http.Request, func()):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			f.(func(http.ResponseWriter, *http.Request, func()))(w, r, q)
		}
	case func(http.ResponseWriter, *http.Request):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			f.(func(http.ResponseWriter, *http.Request))(w, r)
		}
	case http.Handler:
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			f.(http.Handler).ServeHTTP(w, r)
		}
	default:
		panic(ErrUnsupportedHandler)
	}
}

// Compose composes multiple ContextHandlers into a single ContextHandler.
func Compose(stack ...interface{}) ContextHandler {
	contextStack := make([]ContextHandler, 0, len(stack))
	for i := range stack {
		m := ToContextHandler(stack[i])

		contextStack = append(contextStack, m)
	}

	return func(c Context, w http.ResponseWriter, r *http.Request, quit func()) {
		quitStack := false

		for _, m := range contextStack {
			m(c, w, r, func() {
				quitStack = true
			})

			if quitStack {
				quit()
				break
			}
		}
	}
}
<commit_msg>Simplify the type switch<commit_after>package siesta

import (
	"errors"
	"net/http"
)

var ErrUnsupportedHandler = errors.New("siesta: unsupported handler")

// ContextHandler is a siesta handler.
type ContextHandler func(Context, http.ResponseWriter, *http.Request, func())

func (h ContextHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h(EmptyContext{}, w, r, nil)
}

func (h ContextHandler) ServeHTTPInContext(c Context, w http.ResponseWriter, r *http.Request) {
	h(c, w, r, nil)
}

// ToContextHandler transforms f into a ContextHandler.
// f must be a function with one of the following signatures:
//     func(http.ResponseWriter, *http.Request)
//     func(http.ResponseWriter, *http.Request, func())
//     func(Context, http.ResponseWriter, *http.Request)
//     func(Context, http.ResponseWriter, *http.Request, func())
func ToContextHandler(f interface{}) ContextHandler {
	switch t := f.(type) {
	case func(Context, http.ResponseWriter, *http.Request, func()):
		return ContextHandler(t)
	case ContextHandler:
		return t
	case func(Context, http.ResponseWriter, *http.Request):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			t(c, w, r)
		}
	case func(http.ResponseWriter, *http.Request, func()):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			t(w, r, q)
		}
	case func(http.ResponseWriter, *http.Request):
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			t(w, r)
		}
	case http.Handler:
		return func(c Context, w http.ResponseWriter, r *http.Request, q func()) {
			t.ServeHTTP(w, r)
		}
	default:
		panic(ErrUnsupportedHandler)
	}
}

// Compose composes multiple ContextHandlers into a single ContextHandler.
func Compose(stack ...interface{}) ContextHandler {
	contextStack := make([]ContextHandler, 0, len(stack))
	for i := range stack {
		m := ToContextHandler(stack[i])

		contextStack = append(contextStack, m)
	}

	return func(c Context, w http.ResponseWriter, r *http.Request, quit func()) {
		quitStack := false

		for _, m := range contextStack {
			m(c, w, r, func() {
				quitStack = true
			})

			if quitStack {
				quit()
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>package cookie

// Functions for generating random strings

import (
	"math/rand"
)

// RandomString generates a random string of a given length.
func RandomString(length int) string {
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		b[i] = byte(rand.Int63() & 0xff)
	}
	return string(b)
}

// RandomHumanFriendlyString generates a random, but human-friendly, string of
// the given length. It should be possible to read out loud and send in an email
// without problems. The string alternates between vowels and consontants.
// Example output for lenght 10: ykyzexebub
func RandomHumanFriendlyString(length int) string {
	const (
		vowels     = "aeiouy" // email+browsers didn't like "æøå" too much
		consonants = "bcdfghjklmnpqrstvwxz"
	)
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		if i%2 == 0 {
			b[i] = vowels[rand.Intn(len(vowels))]
		} else {
			b[i] = consonants[rand.Intn(len(consonants))]
		}
	}
	return string(b)
}

// RandomCookieFriendlyString generates a random, but cookie-friendly, string of
// the given length.
func RandomCookieFriendlyString(length int) string {
	const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		b[i] = allowed[rand.Intn(len(allowed))]
	}
	return string(b)
}
<commit_msg>Correct a typo in a comment<commit_after>package cookie

// Functions for generating random strings

import (
	"math/rand"
)

// RandomString generates a random string of a given length.
func RandomString(length int) string {
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		b[i] = byte(rand.Int63() & 0xff)
	}
	return string(b)
}

/*RandomHumanFriendlyString generates a random, but human-friendly, string of
 * the given length. It should be possible to read out loud and send in an email
 * without problems. The string alternates between vowels and consontants.
 *
 * Example output for length 10: ykyzexebub
 */
func RandomHumanFriendlyString(length int) string {
	const (
		vowels     = "aeiouy" // email+browsers didn't like "æøå" too much
		consonants = "bcdfghjklmnpqrstvwxz"
	)
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		if i%2 == 0 {
			b[i] = vowels[rand.Intn(len(vowels))]
		} else {
			b[i] = consonants[rand.Intn(len(consonants))]
		}
	}
	return string(b)
}

// RandomCookieFriendlyString generates a random, but cookie-friendly, string of
// the given length.
func RandomCookieFriendlyString(length int) string {
	const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := 0; i < length; i++ {
		b[i] = allowed[rand.Intn(len(allowed))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>// Copyright 2011 Rodrigo Moraes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

import (
	"fmt"
	"http"
	"os"
	"path"
	"gorilla.googlecode.com/hg/gorilla/context"
)

// All error descriptions.
const (
	errRouteName        string = "Duplicated route name: %q."
	errVarName          string = "Duplicated route variable name: %q."
	// Template parsing.
	errUnbalancedBraces string = "Unbalanced curly braces in route template: %q."
	errBadTemplatePart  string = "Missing name or pattern in route template: %q."
	// URL building.
	errMissingRouteVar  string = "Missing route variable: %q."
	errBadRouteVar      string = "Route variable doesn't match: got %q, expected %q."
	errMissingHost      string = "Route doesn't have a host."
	errMissingPath      string = "Route doesn't have a path."
	// Empty parameter errors.
	errEmptyHost        string = "Host() requires a non-zero string, got %q."
	errEmptyPath        string = "Path() requires a non-zero string that starts with a slash, got %q."
	errEmptyPathPrefix  string = "PathPrefix() requires a non-zero string that starts with a slash, got %q."
	// Variadic errors.
	errEmptyHeaders     string = "Headers() requires at least a pair of parameters."
	errEmptyMethods     string = "Methods() requires at least one parameter."
	errEmptyQueries     string = "Queries() requires at least a pair of parameters."
	errEmptySchemes     string = "Schemes() requires at least one parameter."
	errOddHeaders       string = "Headers() requires an even number of parameters, got %v."
	errOddQueries       string = "Queries() requires an even number of parameters, got %v."
	errOddURLPairs      string = "URL() requires an even number of parameters, got %v."
)

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// Vars stores the variables extracted from a URL.
type RouteVars map[string]string

// ctx is the request context namespace for this package.
//
// It stores route variables for each request.
var ctx = new(context.Namespace)

// Vars returns the route variables for the matched route in a given request.
func Vars(request *http.Request) RouteVars {
	rv := ctx.Get(request)
	if rv != nil {
		return rv.(RouteVars)
	}
	return nil
}

// ----------------------------------------------------------------------------
// Router
// ----------------------------------------------------------------------------

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests. For example, using the default router:
//
//     func main() {
//         http.ListenAndServe(":8080", mux.DefaultRouter)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         // Send all incoming requests to mux.DefaultRouter.
//         http.Handle("/", mux.DefaultRouter)
//     }
//
// The DefaultRouter is a Router instance ready to register URLs and handlers.
// If needed, new instances can be created and registered.
type Router struct {
	// Routes to be matched, in order.
	Routes      []*Route
	// Routes by name, for URL building.
	NamedRoutes map[string]*Route
	// Reference to the root router, where named routes are stored.
	rootRouter  *Router
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
}

// root returns the root router, where named routes are stored.
func (r *Router) root() *Router {
	if r.rootRouter == nil {
		return r
	}
	return r.rootRouter
}

// Match matches registered routes against the request.
func (r *Router) Match(request *http.Request) (rv *Route, ok bool) {
	for _, route := range r.Routes {
		if rv, ok = route.Match(request); ok {
			return
		}
	}
	return
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	// Clean path to canonical form and redirect.
	// (this comes from the http package)
	if p := cleanPath(request.URL.Path); p != request.URL.Path {
		writer.Header().Set("Location", p)
		writer.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var handler http.Handler
	if route, ok := r.Match(request); ok {
		handler = route.GetHandler()
	}
	if handler == nil {
		if r.NotFoundHandler == nil {
			r.NotFoundHandler = http.NotFoundHandler()
		}
		handler = r.NotFoundHandler
	}
	defer context.DefaultContext.Clear(request)
	handler.ServeHTTP(writer, request)
}

// AddRoute registers a route in the router.
func (r *Router) AddRoute(route *Route) *Router {
	if r.Routes == nil {
		r.Routes = make([]*Route, 0)
	}
	route.router = r
	r.Routes = append(r.Routes, route)
	return r
}

// Convenience route factories ------------------------------------------------

// NewRoute creates an empty route and registers it in the router.
func (r *Router) NewRoute() *Route {
	route := newRoute()
	r.AddRoute(route)
	return route
}

// Handler registers a new route and sets a handler.
//
// See also: Route.Handler().
func (r *Router) Handler(handler http.Handler) *Route {
	return r.NewRoute().Handler(handler)
}

// HandlerFunc registers a new route and sets a handler function.
//
// See also: Route.HandlerFunc().
func (r *Router) HandlerFunc(handler func(http.ResponseWriter,
							 *http.Request)) *Route {
	return r.NewRoute().HandlerFunc(handler)
}

// Handle registers a new route and sets a path and handler.
//
// See also: Route.Handle().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Handle(path, handler)
}

// HandleFunc registers a new route and sets a path and handler function.
//
// See also: Route.HandleFunc().
func (r *Router) HandleFunc(path string, handler func(http.ResponseWriter,
							*http.Request)) *Route {
	return r.NewRoute().HandleFunc(path, handler)
}

// Name registers a new route and sets the route name.
//
// See also: Route.Name().
func (r *Router) Name(name string) *Route {
	return r.NewRoute().Name(name)
}

// Convenience route matcher factories ----------------------------------------

// Headers registers a new route and sets a headers matcher.
//
// See also: Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route and sets a host matcher.
//
// See also: Route.Host().
func (r *Router) Host(template string) *Route {
	return r.NewRoute().Host(template)
}

// Matcher registers a new route and sets a custom matcher function.
//
// See also: Route.Matcher().
func (r *Router) Matcher(matcherFunc MatcherFunc) *Route {
	return r.NewRoute().Matcher(matcherFunc)
}

// Methods registers a new route and sets a methods matcher.
//
// See also: Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route and sets a path matcher.
//
// See also: Route.Path().
func (r *Router) Path(template string) *Route {
	return r.NewRoute().Path(template)
}

// PathPrefix registers a new route and sets a path prefix matcher.
//
// See also: Route.PathPrefix().
func (r *Router) PathPrefix(template string) *Route {
	return r.NewRoute().PathPrefix(template)
}

// Queries registers a new route and sets a queries matcher.
//
// See also: Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route and sets a schemes matcher.
//
// See also: Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// muxError returns a formatted error.
func muxError(msg string, vars ...interface{}) os.Error {
	return os.NewError(fmt.Sprintf(msg, vars...))
}

// cleanPath returns the canonical path for p, eliminating . and .. elements.
//
// Extracted from the http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}
<commit_msg>Doc fix suggested by Andrew Gerrand.<commit_after>// Copyright 2011 Rodrigo Moraes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

import (
	"fmt"
	"http"
	"os"
	"path"
	"gorilla.googlecode.com/hg/gorilla/context"
)

// All error descriptions.
const (
	errRouteName        string = "Duplicated route name: %q."
	errVarName          string = "Duplicated route variable name: %q."
	// Template parsing.
	errUnbalancedBraces string = "Unbalanced curly braces in route template: %q."
	errBadTemplatePart  string = "Missing name or pattern in route template: %q."
	// URL building.
	errMissingRouteVar  string = "Missing route variable: %q."
	errBadRouteVar      string = "Route variable doesn't match: got %q, expected %q."
	errMissingHost      string = "Route doesn't have a host."
	errMissingPath      string = "Route doesn't have a path."
	// Empty parameter errors.
	errEmptyHost        string = "Host() requires a non-zero string, got %q."
	errEmptyPath        string = "Path() requires a non-zero string that starts with a slash, got %q."
	errEmptyPathPrefix  string = "PathPrefix() requires a non-zero string that starts with a slash, got %q."
	// Variadic errors.
	errEmptyHeaders     string = "Headers() requires at least a pair of parameters."
	errEmptyMethods     string = "Methods() requires at least one parameter."
	errEmptyQueries     string = "Queries() requires at least a pair of parameters."
	errEmptySchemes     string = "Schemes() requires at least one parameter."
	errOddHeaders       string = "Headers() requires an even number of parameters, got %v."
	errOddQueries       string = "Queries() requires an even number of parameters, got %v."
	errOddURLPairs      string = "URL() requires an even number of parameters, got %v."
)

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// Vars stores the variables extracted from a URL.
type RouteVars map[string]string

// ctx is the request context namespace for this package.
//
// It stores route variables for each request.
var ctx = new(context.Namespace)

// Vars returns the route variables for the matched route in a given request.
func Vars(request *http.Request) RouteVars {
	rv := ctx.Get(request)
	if rv != nil {
		return rv.(RouteVars)
	}
	return nil
}

// ----------------------------------------------------------------------------
// Router
// ----------------------------------------------------------------------------

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests. For example, to send all incoming requests to the default router:
//
//     func main() {
//         http.Handle("/", mux.DefaultRouter)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", mux.DefaultRouter)
//     }
//
// The DefaultRouter is a Router instance ready to register URLs and handlers.
// If needed, new instances can be created and registered.
type Router struct {
	// Routes to be matched, in order.
	Routes      []*Route
	// Routes by name, for URL building.
	NamedRoutes map[string]*Route
	// Reference to the root router, where named routes are stored.
	rootRouter  *Router
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
}

// root returns the root router, where named routes are stored.
func (r *Router) root() *Router {
	if r.rootRouter == nil {
		return r
	}
	return r.rootRouter
}

// Match matches registered routes against the request.
func (r *Router) Match(request *http.Request) (rv *Route, ok bool) {
	for _, route := range r.Routes {
		if rv, ok = route.Match(request); ok {
			return
		}
	}
	return
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	// Clean path to canonical form and redirect.
	// (this comes from the http package)
	if p := cleanPath(request.URL.Path); p != request.URL.Path {
		writer.Header().Set("Location", p)
		writer.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var handler http.Handler
	if route, ok := r.Match(request); ok {
		handler = route.GetHandler()
	}
	if handler == nil {
		if r.NotFoundHandler == nil {
			r.NotFoundHandler = http.NotFoundHandler()
		}
		handler = r.NotFoundHandler
	}
	defer context.DefaultContext.Clear(request)
	handler.ServeHTTP(writer, request)
}

// AddRoute registers a route in the router.
func (r *Router) AddRoute(route *Route) *Router {
	if r.Routes == nil {
		r.Routes = make([]*Route, 0)
	}
	route.router = r
	r.Routes = append(r.Routes, route)
	return r
}

// Convenience route factories ------------------------------------------------

// NewRoute creates an empty route and registers it in the router.
func (r *Router) NewRoute() *Route {
	route := newRoute()
	r.AddRoute(route)
	return route
}

// Handler registers a new route and sets a handler.
//
// See also: Route.Handler().
func (r *Router) Handler(handler http.Handler) *Route {
	return r.NewRoute().Handler(handler)
}

// HandlerFunc registers a new route and sets a handler function.
//
// See also: Route.HandlerFunc().
func (r *Router) HandlerFunc(handler func(http.ResponseWriter,
							 *http.Request)) *Route {
	return r.NewRoute().HandlerFunc(handler)
}

// Handle registers a new route and sets a path and handler.
//
// See also: Route.Handle().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Handle(path, handler)
}

// HandleFunc registers a new route and sets a path and handler function.
//
// See also: Route.HandleFunc().
func (r *Router) HandleFunc(path string, handler func(http.ResponseWriter,
							*http.Request)) *Route {
	return r.NewRoute().HandleFunc(path, handler)
}

// Name registers a new route and sets the route name.
//
// See also: Route.Name().
func (r *Router) Name(name string) *Route {
	return r.NewRoute().Name(name)
}

// Convenience route matcher factories ----------------------------------------

// Headers registers a new route and sets a headers matcher.
//
// See also: Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route and sets a host matcher.
//
// See also: Route.Host().
func (r *Router) Host(template string) *Route {
	return r.NewRoute().Host(template)
}

// Matcher registers a new route and sets a custom matcher function.
//
// See also: Route.Matcher().
func (r *Router) Matcher(matcherFunc MatcherFunc) *Route {
	return r.NewRoute().Matcher(matcherFunc)
}

// Methods registers a new route and sets a methods matcher.
//
// See also: Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route and sets a path matcher.
//
// See also: Route.Path().
func (r *Router) Path(template string) *Route {
	return r.NewRoute().Path(template)
}

// PathPrefix registers a new route and sets a path prefix matcher.
//
// See also: Route.PathPrefix().
func (r *Router) PathPrefix(template string) *Route {
	return r.NewRoute().PathPrefix(template)
}

// Queries registers a new route and sets a queries matcher.
//
// See also: Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route and sets a schemes matcher.
//
// See also: Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// muxError returns a formatted error.
func muxError(msg string, vars ...interface{}) os.Error {
	return os.NewError(fmt.Sprintf(msg, vars...))
}

// cleanPath returns the canonical path for p, eliminating . and .. elements.
//
// Extracted from the http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Roy Xu

package redis

type respPubSub interface {
	// PSUBSCRIBE pattern [pattern ...] Listen for messages published to channels matching the given patterns
	// PUBSUB subcommand [argument [argument ...]] Inspect the state of the Pub/Sub subsystem
	// PUBLISH channel message Post a message to a channel
	// PUNSUBSCRIBE [pattern [pattern ...]] Stop listening for messages posted to channels matching the given patterns
	// SUBSCRIBE channel [channel ...] Listen for messages published to the given channels
	// UNSUBSCRIBE [channel [channel ...]] Stop listening for messages posted to the given channels
}
<commit_msg>Create a new branch PubSub<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Roy Xu

package redis

type respPubSub interface {
	// PSUBSCRIBE pattern [pattern ...]
	// Listen for messages published to channels matching the given patterns

	// PUBSUB subcommand [argument [argument ...]]
	// Inspect the state of the Pub/Sub subsystem

	// PUBSUB CHANNELS [pattern]
	// Lists the currently active channels.
	// Array reply: a list of active channels, optionally matching the specified pattern.

	// PUBSUB NUMSUB [channel-1 ... channel-N]
	// Returns the number of subscribers (not counting clients subscribed to patterns) for the specified channels.
	// Array reply:
	//     a list of channels and number of subscribers for every channel.
	//     The format is channel, count, channel, count, ..., so the list is flat.
	//     The order in which the channels are listed is the same as the order of the channels specified in the command call.
	// Note that it is valid to call this command without channels. In this case it will just return an empty list.

	// PUBSUB NUMPAT
	// Returns the number of subscriptions to patterns (that are performed using the PSUBSCRIBE command).
	// Note that this is not just the count of clients subscribed to patterns but the total number of patterns all the clients are subscribed to.
	// Integer reply: the number of patterns all the clients are subscribed to.

	// PUBLISH channel message
	// Post a message to a channel
	// Integer reply: the number of clients that received the message.

	// PUNSUBSCRIBE [pattern [pattern ...]]
	// Stop listening for messages posted to channels matching the given patterns

	// SUBSCRIBE channel [channel ...]
	// Listen for messages published to the given channels

	// UNSUBSCRIBE [channel [channel ...]]
	// Stop listening for messages posted to the given channels
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"html/template"
	"net/http"
)

func renderStatuses(c *gin.Context) {
	query := bson.M{}

	name, ok := c.GetQuery("name")
	if ok && len(name) != 0 {
		query["name"] = bson.RegEx{
			Pattern: `^.*?` + name + `.*$`,
			Options: "i",
		}
	}

	pivot, ok := c.GetQuery("pivot")
	if ok && len(pivot) != 0 {
		query["pivot"] = bson.RegEx{
			Pattern: `^.*?` + pivot + `.*$`,
			Options: "i",
		}
	}

	var results []Status

	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)

	Result := getData(c, collection.Find(query), &results)

	filters := Result["filters"].(gin.H)
	filters["name"] = name
	filters["pivot"] = pivot

	Results, err := json.Marshal(Result)
	if err != nil {
		panic(err.Error())
	}

	if XHR(c) {
		c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
		c.Data(http.StatusOK, "application/json; charset=utf-8", Results)
		return
	}

	c.Set("Results", template.JS(string(Results)))

	c.HTML(http.StatusOK, c.Request.URL.Path, c.Keys)
}

func createStatus(c *gin.Context) {
	response := Response{}
	response.Init(c)
	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not create statuses")
		response.Fail()
		return
	}

	status := Status{}

	decoder := json.NewDecoder(c.Request.Body)
	err := decoder.Decode(&status)
	if err != nil {
		panic(err)
	}

	if len(status.Name) == 0 {
		response.ErrFor["name"] = "required"
	}

	if len(status.Pivot) == 0 {
		response.ErrFor["pivot"] = "required"
	}

	if response.HasErrors() {
		response.Fail()
		return
	}

	//duplicateStatusCheck
	_id := slugify(status.Pivot + " " + status.Name)
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err = collection.FindId(_id).One(nil)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.Errors = append(response.Errors, "That status+pivot is already taken.")
		response.Fail()
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// createStatus
	status.ID = _id

	err = collection.Insert(status)
	if err != nil {
		panic(err)
		return
	}
	response.Finish()
}

func readStatus(c *gin.Context) {

	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	status := Status{}
	collection.FindId(c.Param("id")).One(&status)
	json, err := json.Marshal(status)
	if err != nil {
		panic(err.Error())
	}

	if XHR(c) {
		c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
		c.Data(http.StatusOK, "application/json; charset=utf-8", json)
		return
	}

	c.Set("Record", template.JS(getEscapedString(string(json))))
	c.HTML(http.StatusOK, "/admin/statuses/details/", c.Keys)
}

func updateStatus(c *gin.Context) {
	response := Response{}
	response.Init(c)

	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not create statuses")
		response.Fail()
		return
	}

	status := Status{}

	decoder := json.NewDecoder(c.Request.Body)
	err := decoder.Decode(&status)
	if err != nil {
		panic(err)
		return
	}

	if len(status.Name) == 0 {
		response.ErrFor["name"] = "required"
	}

	if len(status.Pivot) == 0 {
		response.ErrFor["pivot"] = "required"
	}

	if response.HasErrors() {
		response.Fail()
		return
	}

	//duplicateStatusCheck
	_id := slugify(status.Pivot + " " + status.Name)
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err = collection.FindId(_id).One(nil)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.Errors = append(response.Errors, "That status+pivot is already taken.")
		response.Fail()
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// patchStatus
	status.ID = _id
	err = collection.RemoveId(c.Param("id"))
	//println(err.Error())
	err = collection.Insert(status)
	//println(err.Error())
	if err != nil {
		panic(err)
		return
	}

	response.Finish()
}

func deleteStatus(c *gin.Context) {
	response := Response{}
	response.Init(c)

	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not delete statuses.")
		response.Fail()
		return
	}

	// deleteUser
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err := collection.RemoveId(c.Param("id"))
	if err != nil {
		response.Errors = append(response.Errors, err.Error())
		response.Fail()
		return
	}

	response.Finish()
}
<commit_msg>[refactoring] statuses<commit_after>package main

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"html/template"
	"net/http"
)

func renderStatuses(c *gin.Context) {
	query := bson.M{}

	name, ok := c.GetQuery("name")
	if ok && len(name) != 0 {
		query["name"] = bson.RegEx{
			Pattern: `^.*?` + name + `.*$`,
			Options: "i",
		}
	}

	pivot, ok := c.GetQuery("pivot")
	if ok && len(pivot) != 0 {
		query["pivot"] = bson.RegEx{
			Pattern: `^.*?` + pivot + `.*$`,
			Options: "i",
		}
	}

	var statuses []Status

	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)

	Result := getData(c, collection.Find(query), &statuses)

	filters := Result["filters"].(gin.H)
	filters["name"] = name
	filters["pivot"] = pivot

	Results, err := json.Marshal(Result)
	if err != nil {
		panic(err.Error())
	}

	if XHR(c) {
		c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
		c.Data(http.StatusOK, "application/json; charset=utf-8", Results)
		return
	}

	c.Set("Results", template.JS(string(Results)))

	c.HTML(http.StatusOK, c.Request.URL.Path, c.Keys)
}

func createStatus(c *gin.Context) {
	response := newResponse(c)
	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not create statuses")
		response.Fail()
		return
	}

	status := Status{}

	err := json.NewDecoder(c.Request.Body).Decode(&status)
	if err != nil {
		panic(err)
	}

	if len(status.Name) == 0 {
		response.ErrFor["name"] = "required"
	}

	if len(status.Pivot) == 0 {
		response.ErrFor["pivot"] = "required"
	}

	if response.HasErrors() {
		response.Fail()
		return
	}

	//duplicateStatusCheck
	_id := slugify(status.Pivot + " " + status.Name)
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err = collection.FindId(_id).One(nil)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.Errors = append(response.Errors, "That status+pivot is already taken.")
		response.Fail()
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// createStatus
	status.ID = _id

	err = collection.Insert(status)
	if err != nil {
		panic(err)
	}
	response.Finish()
}

func readStatus(c *gin.Context) {
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	status := Status{}
	err := collection.FindId(c.Param("id")).One(&status)
		if err != nil {
		if err == mgo.ErrNotFound {
			renderStatus404(c)
			return
		}
		panic(err)
	}

	json, err := json.Marshal(status)
	if err != nil {
		panic(err.Error())
	}

	if XHR(c) {
		c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
		c.Data(http.StatusOK, "application/json; charset=utf-8", json)
		return
	}

	c.Set("Record", template.JS(getEscapedString(string(json))))
	c.HTML(http.StatusOK, "/admin/statuses/details/", c.Keys)
}

func updateStatus(c *gin.Context) {
	response := newResponse(c)
	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not create statuses.")
		response.Fail()
		return
	}

	status := Status{}

	err := json.NewDecoder(c.Request.Body).Decode(&status)
	if err != nil {
		panic(err)
	}

	if len(status.Name) == 0 {
		response.ErrFor["name"] = "required"
	}

	if len(status.Pivot) == 0 {
		response.ErrFor["pivot"] = "required"
	}

	if response.HasErrors() {
		response.Fail()
		return
	}

	//duplicateStatusCheck
	_id := slugify(status.Pivot + " " + status.Name)
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err = collection.FindId(_id).One(nil)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.Errors = append(response.Errors, "That status+pivot is already taken.")
		response.Fail()
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// patchStatus
	status.ID = _id
	err = collection.RemoveId(c.Param("id")) // c.Param("id") is string/ no bson.ObjectID
	if err != nil {
		panic(err)
	}
	err = collection.Insert(status)
	if err != nil {
		panic(err)
	}

	response.Finish()
}

func deleteStatus(c *gin.Context) {
	response := newResponse(c)
	admin := getAdmin(c)

	// validate
	ok := admin.IsMemberOf(ROOTGROUP)
	if !ok {
		response.Errors = append(response.Errors, "You may not delete statuses.")
		response.Fail()
		return
	}

	// deleteUser
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(STATUSES)
	err := collection.RemoveId(c.Param("id")) // c.Param("id") is string/ no bson.ObjectID
	if err != nil {
		panic(err)
	}

	response.Finish()
}
<|endoftext|>