<commit_before>// Copyright 2015 Lukas Weber. All rights reserved.
// Use of this source code is governed by the MIT-styled
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"strings"

	termbox "github.com/nsf/termbox-go"
)

// A Buffer is a screen of the ui. Buffers are opened on a stack.
type Buffer interface {
	// Draw content on the screen
	Draw()
	// Title displayed in the bottom bar. It has to identify buffer uniquely.
	Title() string
	// Name of the buffer
	Name() string
	// Close the Buffer
	Close()

	// HandleCommand handles string commands. If it returns bool, the
	// command was accepted. If not, it was invalid.
	HandleCommand(cmd string, args []string, stack *BufferStack) bool
}

// BufferStack is the Stack structure managing drawing of the screen and
// buffers.
type BufferStack struct {
	buffers []Buffer

	prompt Prompt
}

func invalidCommand(cmd string) {
	StatusLine = "invalid command: " + cmd
}

// Init initializes the BufferStack and executes the initial command set in Config.
func (b *BufferStack) Init() {
	fields := strings.Fields(config.General.Initial_Command)
	if len(fields) > 0 {
		accept := b.handleCommand(fields[0], fields[1:])
		if !accept {
			invalidCommand(fields[0])
		}
		if len(b.buffers) == 0 {
			b.Push(NewSearchBuffer("", STMessages))
		}
	}
}

// Push pushes a new buffer on the stack. Focus is changed to that buffer.
func (b *BufferStack) Push(n Buffer) {
	for i, buf := range b.buffers {
		// If the buffer already exists, change to it instead.
		if buf.Name() == n.Name() && buf.Title() == n.Title() {
			n.Close()
			copy(b.buffers[i:], b.buffers[i+1:])
			b.buffers[len(b.buffers)-1] = buf
			b.refresh()
			return
		}
	}
	b.buffers = append(b.buffers, n)
	b.refresh()
}

// StatusLine is displayed at the bottom of the screen. useful for error messages.
var StatusLine string

// Pop pops the last buffer from the stack.
func (b *BufferStack) Pop() {
	if len(b.buffers) == 0 {
		return
	}
	b.buffers[len(b.buffers)-1].Close()
	b.buffers = b.buffers[:len(b.buffers)-1]
	b.refresh()
}

// refresh clears the terminal and redraws everything.
func (b *BufferStack) refresh() {
	termbox.Clear(0, 0)
	if len(b.buffers) == 0 {
		return
	}
	b.buffers[len(b.buffers)-1].HandleCommand("_refresh", nil, b)
	b.buffers[len(b.buffers)-1].Draw()
	w, h := termbox.Size()
	cbuf := termbox.CellBuffer()
	for i := 0; i < w; i++ {
		cbuf[(h-2)*w+i].Bg = termbox.Attribute(config.Theme.BottomBar)
		cbuf[(h-2)*w+i].Fg = termbox.AttrBold
	}
	title := b.buffers[len(b.buffers)-1].Title()
	name := b.buffers[len(b.buffers)-1].Name()
	printLine(0, h-2, fmt.Sprintf("[%d: %s] %s", len(b.buffers)-1, name, title), -1, -1)
	if b.prompt.Active() {
		b.prompt.Draw()
	} else if StatusLine != "" {
		_, h := termbox.Size()
		printLine(0, h-1, StatusLine, -1, -1)
	}
	termbox.Flush()
}

// handleCommand executes global commands.
func (b *BufferStack) handleCommand(cmd string, args []string) bool {
	switch cmd {
	case "close":
		b.Pop()
	case "quit":
		for _, buf := range b.buffers {
			buf.Close()
		}
		b.buffers = nil
	case "search":
		b.Push(NewSearchBuffer(strings.Join(args, " "), STThreads))
	case "msearch":
		b.Push(NewSearchBuffer(strings.Join(args, " "), STMessages))
	case "compose":
		b.Push(NewComposeBuffer(composeMail()))
	case "help":
		b.Push(&HelpBuffer{b.buffers[len(b.buffers)-1].Name()})
	case "prompt":
		StatusLine = ""
		b.prompt.Activate(strings.Join(args, " "))
	case "refresh":
		StatusLine = "view refreshed."
		for _, buf := range b.buffers {
			buf.HandleCommand("_refresh", nil, b)
		}
		b.refresh()
	default:
		return false
	}
	return true
}

// HandleEvent handles termbox events and invokes commands if their keybinding was pressed.
func (b *BufferStack) HandleEvent(event *termbox.Event) {
	if len(b.buffers) == 0 {
		return
	}
	if event.Type == termbox.EventResize {
		termbox.Flush()
		for _, buf := range b.buffers {
			buf.HandleCommand("resize", nil, b)
		}
		b.refresh()
		return
	}

	if event.Type == termbox.EventKey {
		if b.prompt.Active() {
			cmd, args := b.prompt.HandleEvent(event)
			if len(cmd) != 0 {
				accept := b.buffers[len(b.buffers)-1].HandleCommand(cmd, args, b)
				if !accept {
					accept = b.handleCommand(cmd, args)
				}
				if !accept {
					invalidCommand(cmd)
				}
				_, h := termbox.Size()
				printLine(0, h-1, StatusLine, -1, -1)
			}
			return
		}
		cmd := getBinding("", event.Ch, event.Key)
		accept := false
		if cmd == nil {
			cmd = getBinding(b.buffers[len(b.buffers)-1].Name(), event.Ch, event.Key)
			if cmd == nil {
				return
			}
		}
		accept = b.buffers[len(b.buffers)-1].HandleCommand(cmd.Command, cmd.Args, b)
		if !accept {
			accept = b.handleCommand(cmd.Command, cmd.Args)
		}
		if !accept {
			invalidCommand(cmd.Command)
		}

		if StatusLine != "" {
			_, h := termbox.Size()
			printLine(0, h-1, StatusLine, -1, -1)
		}
	}

}
<commit_msg>make status line less persistent<commit_after>// Copyright 2015 Lukas Weber. All rights reserved.
// Use of this source code is governed by the MIT-styled
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"strings"

	termbox "github.com/nsf/termbox-go"
)

// A Buffer is a screen of the ui. Buffers are opened on a stack.
type Buffer interface {
	// Draw content on the screen
	Draw()
	// Title displayed in the bottom bar. It has to identify buffer uniquely.
	Title() string
	// Name of the buffer
	Name() string
	// Close the Buffer
	Close()

	// HandleCommand handles string commands. If it returns bool, the
	// command was accepted. If not, it was invalid.
	HandleCommand(cmd string, args []string, stack *BufferStack) bool
}

// BufferStack is the Stack structure managing drawing of the screen and
// buffers.
type BufferStack struct {
	buffers []Buffer

	prompt Prompt
}

func invalidCommand(cmd string) {
	StatusLine = "invalid command: " + cmd
}

// Init initializes the BufferStack and executes the initial command set in Config.
func (b *BufferStack) Init() {
	fields := strings.Fields(config.General.Initial_Command)
	if len(fields) > 0 {
		accept := b.handleCommand(fields[0], fields[1:])
		if !accept {
			invalidCommand(fields[0])
		}
		if len(b.buffers) == 0 {
			b.Push(NewSearchBuffer("", STMessages))
		}
	}
}

// Push pushes a new buffer on the stack. Focus is changed to that buffer.
func (b *BufferStack) Push(n Buffer) {
	for i, buf := range b.buffers {
		// If the buffer already exists, change to it instead.
		if buf.Name() == n.Name() && buf.Title() == n.Title() {
			n.Close()
			copy(b.buffers[i:], b.buffers[i+1:])
			b.buffers[len(b.buffers)-1] = buf
			b.refresh()
			return
		}
	}
	b.buffers = append(b.buffers, n)
	b.refresh()
}

// StatusLine is displayed at the bottom of the screen. useful for error messages.
var StatusLine string

// Pop pops the last buffer from the stack.
func (b *BufferStack) Pop() {
	if len(b.buffers) == 0 {
		return
	}
	b.buffers[len(b.buffers)-1].Close()
	b.buffers = b.buffers[:len(b.buffers)-1]
	b.refresh()
}

// refresh clears the terminal and redraws everything.
func (b *BufferStack) refresh() {
	termbox.Clear(0, 0)
	if len(b.buffers) == 0 {
		return
	}
	b.buffers[len(b.buffers)-1].HandleCommand("_refresh", nil, b)
	b.buffers[len(b.buffers)-1].Draw()
	w, h := termbox.Size()
	cbuf := termbox.CellBuffer()
	for i := 0; i < w; i++ {
		cbuf[(h-2)*w+i].Bg = termbox.Attribute(config.Theme.BottomBar)
		cbuf[(h-2)*w+i].Fg = termbox.AttrBold
	}
	title := b.buffers[len(b.buffers)-1].Title()
	name := b.buffers[len(b.buffers)-1].Name()
	printLine(0, h-2, fmt.Sprintf("[%d: %s] %s", len(b.buffers)-1, name, title), -1, -1)
	if b.prompt.Active() {
		b.prompt.Draw()
	} else if StatusLine != "" {
		_, h := termbox.Size()
		printLine(0, h-1, StatusLine, -1, -1)
	}
	termbox.Flush()
}

// handleCommand executes global commands.
func (b *BufferStack) handleCommand(cmd string, args []string) bool {
	switch cmd {
	case "close":
		b.Pop()
	case "quit":
		for _, buf := range b.buffers {
			buf.Close()
		}
		b.buffers = nil
	case "search":
		b.Push(NewSearchBuffer(strings.Join(args, " "), STThreads))
	case "msearch":
		b.Push(NewSearchBuffer(strings.Join(args, " "), STMessages))
	case "compose":
		b.Push(NewComposeBuffer(composeMail()))
	case "help":
		b.Push(&HelpBuffer{b.buffers[len(b.buffers)-1].Name()})
	case "prompt":
		StatusLine = ""
		b.prompt.Activate(strings.Join(args, " "))
	case "refresh":
		StatusLine = "view refreshed."
		for _, buf := range b.buffers {
			buf.HandleCommand("_refresh", nil, b)
		}
		b.refresh()
	default:
		return false
	}
	return true
}

// HandleEvent handles termbox events and invokes commands if their keybinding was pressed.
func (b *BufferStack) HandleEvent(event *termbox.Event) {
	if len(b.buffers) == 0 {
		return
	}
	if event.Type == termbox.EventResize {
		termbox.Flush()
		for _, buf := range b.buffers {
			buf.HandleCommand("resize", nil, b)
		}
		b.refresh()
		return
	}

	if event.Type == termbox.EventKey {
		StatusLine = ""
		if b.prompt.Active() {
			cmd, args := b.prompt.HandleEvent(event)
			if len(cmd) != 0 {
				accept := b.buffers[len(b.buffers)-1].HandleCommand(cmd, args, b)
				if !accept {
					accept = b.handleCommand(cmd, args)
				}
				if !accept {
					invalidCommand(cmd)
				}
				_, h := termbox.Size()
				printLine(0, h-1, StatusLine, -1, -1)
			}
			return
		}
		cmd := getBinding("", event.Ch, event.Key)
		accept := false
		if cmd == nil {
			cmd = getBinding(b.buffers[len(b.buffers)-1].Name(), event.Ch, event.Key)
			if cmd == nil {
				return
			}
		}
		accept = b.buffers[len(b.buffers)-1].HandleCommand(cmd.Command, cmd.Args, b)
		if !accept {
			accept = b.handleCommand(cmd.Command, cmd.Args)
		}
		if !accept {
			invalidCommand(cmd.Command)
		}

		if StatusLine != "" {
			_, h := termbox.Size()
			printLine(0, h-1, StatusLine, -1, -1)
		}
	}

}
<|endoftext|>


<commit_before>// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix

package sftp

import (
	"os"
	"syscall"
)

func fileStatFromInfoOs(fi os.FileInfo, flags *uint32, fileStat *FileStat) {
	if statt, ok := fi.Sys().(*syscall.Stat_t); ok {
		*flags |= sshFileXferAttrUIDGID
		fileStat.UID = statt.Uid
		fileStat.GID = statt.Gid
	}
}
<commit_msg>js's Stat_t conforms to attrs_unix.go<commit_after>// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix js

package sftp

import (
	"os"
	"syscall"
)

func fileStatFromInfoOs(fi os.FileInfo, flags *uint32, fileStat *FileStat) {
	if statt, ok := fi.Sys().(*syscall.Stat_t); ok {
		*flags |= sshFileXferAttrUIDGID
		fileStat.UID = statt.Uid
		fileStat.GID = statt.Gid
	}
}
<|endoftext|>


<commit_before>package sshutils

// Copyright (c) 2017, Harrison Feng
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package includes ssh utilities implemented by Golang.
// @author Harrison Feng <feng.harrison@gmail.com>

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/ssh"
	"log"
)

func GetSshConfig(user string, password string) *ssh.ClientConfig {

	config := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) {
				// Just send the password back for all questions
				answers := make([]string, len(questions))
				for i, _ := range answers {
					answers[i] = password
				}
				return answers, nil
			}),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	return config

}

func ExecSshCmd(cmd string, hostname string, port string, config *ssh.ClientConfig) (string, error) {

	var b bytes.Buffer

	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", hostname, port), config)
	if err != nil {
		log.Fatal("Failed to dail: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	session.Stdout = &b

	if err := session.Run(cmd); err != nil {
		log.Fatal("Failed to run: " + err.Error())
		return b.String(), err
	}

	o := b.String()

	return o, nil
}

func Service(params map[string]string, name string, action string, su bool) error {

	var cmd string

	conf := GetSshConfig(params["user"], params["password"])

	if su == true {
		// This requires the user has the same password as root.
		cmd = fmt.Sprintf("echo '%s' | su -c 'service %s %s' root",
			params["password"],
			name,
			action)
	} else {
		cmd = fmt.Sprintf("service %s %s", name, action)
	}

	_, err := ExecSshCmd(cmd, params["hostname"], "22", conf)
	if err != nil {
		return err
	}

	return nil

}

func DownloadWithCurl(params map[string]string, url string, targetDir string, su bool) error {

	var cmd string

	if su == true {
		// This requires the user has the same password as root.
		cmd = fmt.Sprintf("echo '%s' | su -c 'cd %s && curl -O %s' root",
			params["password"],
			targetDir,
			url)
	} else {
		cmd = fmt.Sprint("cd %s && curl -O %s", targetDir, url)
	}

	conf := GetSshConfig(params["user"], params["password"])

	_, err := ExecSshCmd(cmd, params["hostname"], "22", conf)
	if err != nil {
		log.Fatal(err)
		return err
	}

	return nil

}
<commit_msg>add comments for methods<commit_after>// Copyright (c) 2017, Harrison Feng
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package includes ssh utilities implemented by Golang.
// @author Harrison Feng <feng.harrison@gmail.com>

package sshutils

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/ssh"
	"log"
)

func GetSshConfig(user string, password string) *ssh.ClientConfig {

	config := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) {
				// Just send the password back for all questions
				answers := make([]string, len(questions))
				for i, _ := range answers {
					answers[i] = password
				}
				return answers, nil
			}),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	return config

}

// Execute command in remote server by SSH
func ExecSshCmd(cmd string, hostname string, port string, config *ssh.ClientConfig) (string, error) {

	var b bytes.Buffer

	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", hostname, port), config)
	if err != nil {
		log.Fatal("Failed to dail: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	session.Stdout = &b

	if err := session.Run(cmd); err != nil {
		log.Fatal("Failed to run: " + err.Error())
		return b.String(), err
	}

	o := b.String()

	return o, nil
}

// Manage various service in remote server.
func Service(params map[string]string, name string, action string, su bool) error {

	var cmd string

	conf := GetSshConfig(params["user"], params["password"])

	if su == true {
		// This requires the user has the same password as root.
		cmd = fmt.Sprintf("echo '%s' | su -c 'service %s %s' root",
			params["password"],
			name,
			action)
	} else {
		cmd = fmt.Sprintf("service %s %s", name, action)
	}

	_, err := ExecSshCmd(cmd, params["hostname"], "22", conf)
	if err != nil {
		return err
	}

	return nil

}

// Download a file to the target directory of remote server.
func DownloadWithCurl(params map[string]string, url string, targetDir string, su bool) error {

	var cmd string

	if su == true {
		// This requires the user has the same password as root.
		cmd = fmt.Sprintf("echo '%s' | su -c 'cd %s && curl -O %s' root",
			params["password"],
			targetDir,
			url)
	} else {
		cmd = fmt.Sprint("cd %s && curl -O %s", targetDir, url)
	}

	conf := GetSshConfig(params["user"], params["password"])

	_, err := ExecSshCmd(cmd, params["hostname"], "22", conf)
	if err != nil {
		log.Fatal(err)
		return err
	}

	return nil

}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
)

func TestAccAWSDataElasticsearchDomain_basic(t *testing.T) {
	rInt := acctest.RandInt()
	datasourceName := "data.aws_elasticsearch_domain.test"
	resourceName := "aws_elasticsearch_domain.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSElasticsearchDomainConfigWithDataSource(rInt),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrPair(datasourceName, "elasticsearch_version", resourceName, "elasticsearch_version"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.#", resourceName, "cluster_config.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_type", resourceName, "cluster_config.0.instance_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_count", resourceName, "cluster_config.0.instance_count"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.dedicated_master_enabled", resourceName, "cluster_config.0.dedicated_master_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.zone_awareness_enabled", resourceName, "cluster_config.0.zone_awareness_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.#", resourceName, "ebs_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.ebs_enabled", resourceName, "ebs_options.0.ebs_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_type", resourceName, "ebs_options.0.volume_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_size", resourceName, "ebs_options.0.volume_size"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.#", resourceName, "snapshot_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.0.automated_snapshot_start_hour", resourceName, "snapshot_options.0.automated_snapshot_start_hour"),
				),
			},
		},
	})
}

func TestAccAWSDataElasticsearchDomain_advanced(t *testing.T) {
	rInt := acctest.RandInt()
	datasourceName := "data.aws_elasticsearch_domain.test"
	resourceName := "aws_elasticsearch_domain.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSElasticsearchDomainConfigAdvancedWithDataSource(rInt),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrPair(datasourceName, "elasticsearch_version", resourceName, "elasticsearch_version"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.#", resourceName, "cluster_config.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_type", resourceName, "cluster_config.0.instance_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_count", resourceName, "cluster_config.0.instance_count"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.dedicated_master_enabled", resourceName, "cluster_config.0.dedicated_master_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.zone_awareness_enabled", resourceName, "cluster_config.0.zone_awareness_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.#", resourceName, "ebs_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.ebs_enabled", resourceName, "ebs_options.0.ebs_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_type", resourceName, "ebs_options.0.volume_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_size", resourceName, "ebs_options.0.volume_size"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.#", resourceName, "snapshot_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.0.automated_snapshot_start_hour", resourceName, "snapshot_options.0.automated_snapshot_start_hour"),
					resource.TestCheckResourceAttrPair(datasourceName, "log_publishing_options.#", resourceName, "log_publishing_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "vpc_options.#", resourceName, "vpc_options.#"),
				),
			},
		},
	})
}

func testAccAWSElasticsearchDomainConfigWithDataSource(rInt int) string {
	return fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}

locals {
	random_name = "test-es-%d"
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

resource "aws_elasticsearch_domain" "test" {
	domain_name = "${local.random_name}"
	elasticsearch_version = "1.5"

	access_policies = <<POLICY
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Action": "es:*",
			"Principal": "*",
			"Effect": "Allow",
			"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/${local.random_name}/*",
			"Condition": {
				"IpAddress": {"aws:SourceIp": ["127.0.0.0/8"]}
			}
		}
	]
}
POLICY

  cluster_config {
    instance_type = "t2.micro.elasticsearch"
    instance_count = 2
	dedicated_master_enabled = false
	zone_awareness_config {
		availability_zone_count = 2
	}
    zone_awareness_enabled = true
  }
  ebs_options {
	ebs_enabled = true
	volume_type = "gp2"
	volume_size = 20
  }
  snapshot_options {
    automated_snapshot_start_hour = 23
  }
}

data "aws_elasticsearch_domain" "test" {
  domain_name = "${aws_elasticsearch_domain.test.domain_name}"
}
		`, rInt)
}

func testAccAWSElasticsearchDomainConfigAdvancedWithDataSource(rInt int) string {
	return fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

locals {
	random_name = "test-es-%d"
}

resource "aws_cloudwatch_log_group" "test" {
	name = "${local.random_name}"
}

resource "aws_cloudwatch_log_resource_policy" "test" {
	policy_name = "${local.random_name}"
	policy_document = <<CONFIG
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "es.amazonaws.com"
			},
			"Action": [
				"logs:PutLogEvents",
				"logs:PutLogEventsBatch",
				"logs:CreateLogStream"
			],
			"Resource": "arn:aws:logs:*"
		}
	]
}
CONFIG
}

resource "aws_vpc" "test" {
	cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "test" {
	vpc_id = "${aws_vpc.test.id}"
	cidr_block = "10.0.0.0/24"
}

resource "aws_subnet" "test2" {
	vpc_id = "${aws_vpc.test.id}"
	cidr_block = "10.0.1.0/24"
}

resource "aws_security_group" "test" {
	name = "${local.random_name}"
	vpc_id = "${aws_vpc.test.id}"
}

resource "aws_security_group_rule" "test" {
	type = "ingress"
	from_port = 443
	to_port = 443
	protocol = "tcp"
	cidr_blocks = [ "0.0.0.0/0" ]

	security_group_id = "${aws_security_group.test.id}"
}

resource "aws_iam_service_linked_role" "test" {
	aws_service_name = "es.amazonaws.com"
}

resource "aws_elasticsearch_domain" "test" {
	domain_name = "${local.random_name}"
	elasticsearch_version = "1.5"

	access_policies = <<POLICY
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Action": "es:*",
			"Principal": "*",
			"Effect": "Allow",
			"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/${local.random_name}/*"
		}
	]
}
POLICY

  cluster_config {
    instance_type = "t2.micro.elasticsearch"
    instance_count = 2
    dedicated_master_enabled = false
	zone_awareness_config {
		availability_zone_count = 2
	}
    zone_awareness_enabled = true
  }
  ebs_options {
	ebs_enabled = true
	volume_type = "gp2"
	volume_size = 20
  }
  snapshot_options {
    automated_snapshot_start_hour = 23
  }
  log_publishing_options {
    cloudwatch_log_group_arn = "${aws_cloudwatch_log_group.test.arn}"
    log_type = "INDEX_SLOW_LOGS"
  }
  vpc_options {
		security_group_ids = [
			"${aws_security_group.test.id}"
		]
		subnet_ids = [
			"${aws_subnet.test.id}",
			"${aws_subnet.test2.id}"
		]
  }

  tags = {
	Domain = "TestDomain"
  }

  depends_on = [
    "aws_iam_service_linked_role.test",
  ]
}

data "aws_elasticsearch_domain" "test" {
  domain_name = "${aws_elasticsearch_domain.test.domain_name}"
}
				`, rInt)
}
<commit_msg>test/data_source/aws_elasticsearch_domain: Remove service role resource creation<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
)

func TestAccAWSDataElasticsearchDomain_basic(t *testing.T) {
	rInt := acctest.RandInt()
	datasourceName := "data.aws_elasticsearch_domain.test"
	resourceName := "aws_elasticsearch_domain.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSElasticsearchDomainConfigWithDataSource(rInt),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrPair(datasourceName, "elasticsearch_version", resourceName, "elasticsearch_version"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.#", resourceName, "cluster_config.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_type", resourceName, "cluster_config.0.instance_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_count", resourceName, "cluster_config.0.instance_count"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.dedicated_master_enabled", resourceName, "cluster_config.0.dedicated_master_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.zone_awareness_enabled", resourceName, "cluster_config.0.zone_awareness_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.#", resourceName, "ebs_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.ebs_enabled", resourceName, "ebs_options.0.ebs_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_type", resourceName, "ebs_options.0.volume_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_size", resourceName, "ebs_options.0.volume_size"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.#", resourceName, "snapshot_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.0.automated_snapshot_start_hour", resourceName, "snapshot_options.0.automated_snapshot_start_hour"),
				),
			},
		},
	})
}

func TestAccAWSDataElasticsearchDomain_advanced(t *testing.T) {
	rInt := acctest.RandInt()
	datasourceName := "data.aws_elasticsearch_domain.test"
	resourceName := "aws_elasticsearch_domain.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSElasticsearchDomainConfigAdvancedWithDataSource(rInt),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrPair(datasourceName, "elasticsearch_version", resourceName, "elasticsearch_version"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.#", resourceName, "cluster_config.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_type", resourceName, "cluster_config.0.instance_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.instance_count", resourceName, "cluster_config.0.instance_count"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.dedicated_master_enabled", resourceName, "cluster_config.0.dedicated_master_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "cluster_config.0.zone_awareness_enabled", resourceName, "cluster_config.0.zone_awareness_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.#", resourceName, "ebs_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.ebs_enabled", resourceName, "ebs_options.0.ebs_enabled"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_type", resourceName, "ebs_options.0.volume_type"),
					resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_size", resourceName, "ebs_options.0.volume_size"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.#", resourceName, "snapshot_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.0.automated_snapshot_start_hour", resourceName, "snapshot_options.0.automated_snapshot_start_hour"),
					resource.TestCheckResourceAttrPair(datasourceName, "log_publishing_options.#", resourceName, "log_publishing_options.#"),
					resource.TestCheckResourceAttrPair(datasourceName, "vpc_options.#", resourceName, "vpc_options.#"),
				),
			},
		},
	})
}

func testAccAWSElasticsearchDomainConfigWithDataSource(rInt int) string {
	return fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}

locals {
	random_name = "test-es-%d"
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

resource "aws_elasticsearch_domain" "test" {
	domain_name = "${local.random_name}"
	elasticsearch_version = "1.5"

	access_policies = <<POLICY
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Action": "es:*",
			"Principal": "*",
			"Effect": "Allow",
			"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/${local.random_name}/*",
			"Condition": {
				"IpAddress": {"aws:SourceIp": ["127.0.0.0/8"]}
			}
		}
	]
}
POLICY

  cluster_config {
    instance_type = "t2.micro.elasticsearch"
    instance_count = 2
	dedicated_master_enabled = false
	zone_awareness_config {
		availability_zone_count = 2
	}
    zone_awareness_enabled = true
  }
  ebs_options {
	ebs_enabled = true
	volume_type = "gp2"
	volume_size = 20
  }
  snapshot_options {
    automated_snapshot_start_hour = 23
  }
}

data "aws_elasticsearch_domain" "test" {
  domain_name = "${aws_elasticsearch_domain.test.domain_name}"
}
		`, rInt)
}

func testAccAWSElasticsearchDomainConfigAdvancedWithDataSource(rInt int) string {
	return fmt.Sprintf(`
provider "aws" {
	region = "us-east-1"
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

locals {
	random_name = "test-es-%d"
}

resource "aws_cloudwatch_log_group" "test" {
	name = "${local.random_name}"
}

resource "aws_cloudwatch_log_resource_policy" "test" {
	policy_name = "${local.random_name}"
	policy_document = <<CONFIG
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "es.amazonaws.com"
			},
			"Action": [
				"logs:PutLogEvents",
				"logs:PutLogEventsBatch",
				"logs:CreateLogStream"
			],
			"Resource": "arn:aws:logs:*"
		}
	]
}
CONFIG
}

resource "aws_vpc" "test" {
	cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "test" {
	vpc_id = "${aws_vpc.test.id}"
	cidr_block = "10.0.0.0/24"
}

resource "aws_subnet" "test2" {
	vpc_id = "${aws_vpc.test.id}"
	cidr_block = "10.0.1.0/24"
}

resource "aws_security_group" "test" {
	name = "${local.random_name}"
	vpc_id = "${aws_vpc.test.id}"
}

resource "aws_security_group_rule" "test" {
	type = "ingress"
	from_port = 443
	to_port = 443
	protocol = "tcp"
	cidr_blocks = [ "0.0.0.0/0" ]

	security_group_id = "${aws_security_group.test.id}"
}

resource "aws_elasticsearch_domain" "test" {
	domain_name = "${local.random_name}"
	elasticsearch_version = "1.5"

	access_policies = <<POLICY
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Action": "es:*",
			"Principal": "*",
			"Effect": "Allow",
			"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/${local.random_name}/*"
		}
	]
}
POLICY

  cluster_config {
    instance_type = "t2.micro.elasticsearch"
    instance_count = 2
    dedicated_master_enabled = false
	zone_awareness_config {
		availability_zone_count = 2
	}
    zone_awareness_enabled = true
  }
  ebs_options {
	ebs_enabled = true
	volume_type = "gp2"
	volume_size = 20
  }
  snapshot_options {
    automated_snapshot_start_hour = 23
  }
  log_publishing_options {
    cloudwatch_log_group_arn = "${aws_cloudwatch_log_group.test.arn}"
    log_type = "INDEX_SLOW_LOGS"
  }
  vpc_options {
		security_group_ids = [
			"${aws_security_group.test.id}"
		]
		subnet_ids = [
			"${aws_subnet.test.id}",
			"${aws_subnet.test2.id}"
		]
  }

  tags = {
	Domain = "TestDomain"
  }
}

data "aws_elasticsearch_domain" "test" {
  domain_name = "${aws_elasticsearch_domain.test.domain_name}"
}
				`, rInt)
}
<|endoftext|>


<commit_before>package registry

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type loginOptions struct {
	serverAddress string
	user          string
	password      string
}

// NewLoginCommand creates a new `docker login` command
func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
	var opts loginOptions

	cmd := &cobra.Command{
		Use:   "login [OPTIONS] [SERVER]",
		Short: "Log in to a Docker registry",
		Long:  "Log in to a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
		Args:  cli.RequiresMaxArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 {
				opts.serverAddress = args[0]
			}
			return runLogin(dockerCli, opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.user, "username", "u", "", "Username")
	flags.StringVarP(&opts.password, "password", "p", "", "Password")

	return cmd
}

func runLogin(dockerCli command.Cli, opts loginOptions) error {
	ctx := context.Background()
	clnt := dockerCli.Client()

	var (
		serverAddress string
		authServer    = command.ElectAuthServer(ctx, dockerCli)
	)
	if opts.serverAddress != "" && opts.serverAddress != registry.DefaultNamespace {
		serverAddress = opts.serverAddress
	} else {
		serverAddress = authServer
	}

	isDefaultRegistry := serverAddress == authServer

	authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry)
	if err != nil {
		return err
	}
	response, err := clnt.RegistryLogin(ctx, authConfig)
	if err != nil {
		return err
	}
	if response.IdentityToken != "" {
		authConfig.Password = ""
		authConfig.IdentityToken = response.IdentityToken
	}
	if err := dockerCli.CredentialsStore(serverAddress).Store(authConfig); err != nil {
		return errors.Errorf("Error saving credentials: %v", err)
	}

	if response.Status != "" {
		fmt.Fprintln(dockerCli.Out(), response.Status)
	}
	return nil
}
<commit_msg>login: print a big warning when using --password<commit_after>package registry

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type loginOptions struct {
	serverAddress string
	user          string
	password      string
}

// NewLoginCommand creates a new `docker login` command
func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
	var opts loginOptions

	cmd := &cobra.Command{
		Use:   "login [OPTIONS] [SERVER]",
		Short: "Log in to a Docker registry",
		Long:  "Log in to a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
		Args:  cli.RequiresMaxArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 {
				opts.serverAddress = args[0]
			}
			return runLogin(dockerCli, opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.user, "username", "u", "", "Username")
	flags.StringVarP(&opts.password, "password", "p", "", "Password")

	return cmd
}

func runLogin(dockerCli command.Cli, opts loginOptions) error {
	ctx := context.Background()
	clnt := dockerCli.Client()

	if opts.password != "" {
		fmt.Fprintln(dockerCli.Err(), "WARNING! Using --password via the CLI is insecure.")
	}

	var (
		serverAddress string
		authServer    = command.ElectAuthServer(ctx, dockerCli)
	)
	if opts.serverAddress != "" && opts.serverAddress != registry.DefaultNamespace {
		serverAddress = opts.serverAddress
	} else {
		serverAddress = authServer
	}

	isDefaultRegistry := serverAddress == authServer

	authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry)
	if err != nil {
		return err
	}
	response, err := clnt.RegistryLogin(ctx, authConfig)
	if err != nil {
		return err
	}
	if response.IdentityToken != "" {
		authConfig.Password = ""
		authConfig.IdentityToken = response.IdentityToken
	}
	if err := dockerCli.CredentialsStore(serverAddress).Store(authConfig); err != nil {
		return errors.Errorf("Error saving credentials: %v", err)
	}

	if response.Status != "" {
		fmt.Fprintln(dockerCli.Out(), response.Status)
	}
	return nil
}
<|endoftext|>


<commit_before>package check

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// stem's ExitPolicyRule class, sort of
type Rule struct {
	IsAccept  bool
	Address   string
	AddressIP net.IP
	MinPort   int
	MaxPort   int
}

func ValidPort(port int) bool {
	return port >= 0 && port < 65536
}

func (r Rule) IsMatch(ap AddressPort) bool {
	address := net.ParseIP(ap.Address)
	if address == nil {
		return false
	}
	if r.AddressIP != nil && !r.AddressIP.Equal(address) {
		return false
	}
	if !ValidPort(ap.Port) || ap.Port < r.MinPort || ap.Port > r.MaxPort {
		return false
	}
	return true
}

type AddressPort struct {
	Address string
	Port    int
}

type Policy struct {
	Address          string
	Rules            []Rule
	IsAllowedDefault bool
	CanExitCache     map[AddressPort]bool
}

func (p Policy) CanExit(ap AddressPort) bool {
	can, ok := p.CanExitCache[ap]
	if !ok {
		can = p.IsAllowedDefault
		for _, rule := range p.Rules {
			if rule.IsMatch(ap) {
				can = rule.IsAccept
				break
			}
		}
		p.CanExitCache[ap] = can
	}
	return can
}

type Exits struct {
	List       map[string]Policy
	UpdateTime time.Time
	ReloadChan chan os.Signal
}

func (e *Exits) Dump(ip string, port int) string {
	ap := AddressPort{ip, port}
	var str string
	for key, val := range e.List {
		if val.CanExit(ap) {
			str += fmt.Sprintf("%s\n", key)
		}
	}
	return str
}

var DefaultTarget = AddressPort{"38.229.70.31", 443}

func (e *Exits) IsTor(remoteAddr string) bool {
	policy, ok := e.List[remoteAddr]
	if ok {
		return policy.CanExit(DefaultTarget)
	}
	return false
}

func (e *Exits) Load() {
	file, err := os.Open("data/exit-policies")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	exits := make(map[string]Policy)
	dec := json.NewDecoder(file)
	for {
		var p Policy
		if err = dec.Decode(&p); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		for _, r := range p.Rules {
			r.AddressIP = net.ParseIP(r.Address)
		}
		p.CanExitCache = make(map[AddressPort]bool)
		exits[p.Address] = p
	}

	// swap in exits
	e.List = exits
	e.UpdateTime = time.Now()
}

func (e *Exits) Run() {
	e.ReloadChan = make(chan os.Signal, 1)
	signal.Notify(e.ReloadChan, syscall.SIGUSR2)
	go func() {
		for {
			<-e.ReloadChan
			e.Load()
			log.Println("Exit list reloaded.")
		}
	}()
	e.Load()
}
<commit_msg>Checking IsTor is now O(1) with precomputing whenever we get new exitlists<commit_after>package check

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// stem's ExitPolicyRule class, sort of
type Rule struct {
	IsAccept  bool
	Address   string
	AddressIP net.IP
	MinPort   int
	MaxPort   int
}

func ValidPort(port int) bool {
	return port >= 0 && port < 65536
}

func (r Rule) IsMatch(ap AddressPort) bool {
	address := net.ParseIP(ap.Address)
	if address == nil {
		return false
	}
	if r.AddressIP != nil && !r.AddressIP.Equal(address) {
		return false
	}
	if !ValidPort(ap.Port) || ap.Port < r.MinPort || ap.Port > r.MaxPort {
		return false
	}
	return true
}

type AddressPort struct {
	Address string
	Port    int
}

type Policy struct {
	Address          string
	Rules            []Rule
	IsAllowedDefault bool
	CanExitCache     map[AddressPort]bool
}

func (p Policy) CanExit(ap AddressPort) bool {
	can, ok := p.CanExitCache[ap]
	if !ok {
		can = p.IsAllowedDefault
		for _, rule := range p.Rules {
			if rule.IsMatch(ap) {
				can = rule.IsAccept
				break
			}
		}
		p.CanExitCache[ap] = can
	}
	return can
}

type Exits struct {
	List        map[string]Policy
	UpdateTime  time.Time
	ReloadChan  chan os.Signal
	isTorLookup map[string]bool
}

func (e *Exits) Dump(ip string, port int) string {
	// This should cause less GC
	var buf bytes.Buffer

	e.getAllExits(ip, port, func(can_exit_ip string) {
		buf.WriteString(can_exit_ip)
		buf.WriteRune('\n')
	})

	return buf.String()
}

func (e *Exits) getAllExits(ip string, port int, fn func(ip string)) {
	ap := AddressPort{ip, port}
	for key, val := range e.List {
		if val.CanExit(ap) {
			fn(key)
		}
	}
}

var DefaultTarget = AddressPort{"38.229.70.31", 443}

func (e *Exits) IsTor(remoteAddr string) bool {
	return e.isTorLookup[remoteAddr]
}

func (e *Exits) Load() {
	file, err := os.Open("data/exit-policies")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	exits := make(map[string]Policy)
	dec := json.NewDecoder(file)
	for {
		var p Policy
		if err = dec.Decode(&p); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		for _, r := range p.Rules {
			r.AddressIP = net.ParseIP(r.Address)
		}
		p.CanExitCache = make(map[AddressPort]bool)
		exits[p.Address] = p
	}

	// swap in exits
	e.List = exits
	e.UpdateTime = time.Now()

	// Precompute after the new list is swapped
	e.preComputeTorList()
}

func (e *Exits) preComputeTorList() {
	newmap := make(map[string]bool)
	e.getAllExits(DefaultTarget.Address, DefaultTarget.Port, func(ip string) {
		newmap[ip] = true
	})

	e.isTorLookup = newmap
}

func (e *Exits) Run() {
	e.ReloadChan = make(chan os.Signal, 1)
	signal.Notify(e.ReloadChan, syscall.SIGUSR2)
	go func() {
		for {
			<-e.ReloadChan
			e.Load()
			log.Println("Exit list reloaded.")
		}
	}()
	e.Load()
}
<|endoftext|>


<commit_before>package database

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	_ "github.com/ClickHouse/clickhouse-go"
)

type Client struct {
	db *sql.DB
}

func NewClient(dsn string) (*Client, error) {
	db, err := sql.Open("clickhouse", dsn)
	if err != nil {
		return nil, fmt.Errorf("open: %v", err)
	}

	return &Client{db: db}, nil
}

func (c *Client) Ping(ctx context.Context) error {
	if c.db == nil {
		return errors.New("nil db")
	}

	return c.db.PingContext(ctx)
}

func (c *Client) Close() error {
	if c.db == nil {
		return errors.New("nil db")
	}

	return c.db.Close()
}

func (c *Client) CreateIfNotExists(ctx context.Context) error {
	if c.db == nil {
		return errors.New("nil db")
	}

	const databaseQuery = "CREATE DATABASE IF NOT EXISTS dojodb"

	_, err := c.db.ExecContext(ctx, databaseQuery)
	if err != nil {
		return fmt.Errorf("create database: %v", err)
	}

	const tableQuery = `CREATE TABLE IF NOT EXISTS dojodb.dojotable
		(
			uid String,
			title String,
			date DateTime
		)
		engine = MergeTree() PARTITION BY toYYYYMM(date) ORDER BY uid SETTINGS index_granularity = 8192;`

	_, err = c.db.ExecContext(ctx, tableQuery)

	return err
}
<commit_msg>clickhouse/database: add Row and InsertRow<commit_after>package database

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"time"

	_ "github.com/ClickHouse/clickhouse-go"
)

type Client struct {
	db *sql.DB
}

func NewClient(dsn string) (*Client, error) {
	db, err := sql.Open("clickhouse", dsn)
	if err != nil {
		return nil, fmt.Errorf("open: %v", err)
	}

	return &Client{db: db}, nil
}

func (c *Client) Ping(ctx context.Context) error {
	if c.db == nil {
		return errors.New("nil db")
	}

	return c.db.PingContext(ctx)
}

func (c *Client) Close() error {
	if c.db == nil {
		return errors.New("nil db")
	}

	return c.db.Close()
}

func (c *Client) CreateIfNotExists(ctx context.Context) error {
	if c.db == nil {
		return errors.New("nil db")
	}

	const databaseQuery = "CREATE DATABASE IF NOT EXISTS dojodb"

	_, err := c.db.ExecContext(ctx, databaseQuery)
	if err != nil {
		return fmt.Errorf("create database: %v", err)
	}

	const tableQuery = `CREATE TABLE IF NOT EXISTS dojodb.dojotable
		(
			uid String,
			title String,
			date DateTime
		)
		engine = MergeTree() PARTITION BY toYYYYMM(date) ORDER BY uid SETTINGS index_granularity = 8192;`

	_, err = c.db.ExecContext(ctx, tableQuery)

	return err
}

type Row struct {
	UID   string
	Title string
	Date  time.Time
}

func (c *Client) InsertRow(ctx context.Context, r Row) error {
	if c.db == nil {
		return errors.New("nil db")
	}

	tx, err := c.db.Begin()
	if err != nil {
		return fmt.Errorf("begin: %v", err)
	}

	const q = `INSERT INTO dojodb.dojotable (uid, title, date) VALUES (?, ?, ?)`

	_, err = tx.ExecContext(ctx, q, r.UID, r.Title, r.Date)
	if err != nil {
		return fmt.Errorf("insert: %v", err)
	}

	return tx.Commit()
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
)

type bqlParser struct {
	b bqlPeg
}

func NewBQLParser() *bqlParser {
	return &bqlParser{}
}

func (p *bqlParser) ParseStmt(s string) (interface{}, error) {
	// parse the statement
	b := p.b
	b.Buffer = s
	b.Init()
	if err := b.Parse(); err != nil {
		return nil, err
	}
	b.Execute()
	if b.parseStack.Peek() == nil {
		// the statement was parsed ok, but not put on the stack?
		// this should never occur.
		return nil, fmt.Errorf("no valid BQL statement could be parsed")
	}
	// pop it from the parse stack
	return b.parseStack.Pop().comp, nil
}
<commit_msg>add panic handling in BQLParser<commit_after>package parser

import (
	"fmt"
)

type bqlParser struct {
	b bqlPeg
}

func NewBQLParser() *bqlParser {
	return &bqlParser{}
}

func (p *bqlParser) ParseStmt(s string) (res interface{}, err error) {
	// catch any parser errors
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Error in BQL parser: %v", r)
		}
	}()
	// parse the statement
	b := p.b
	b.Buffer = s
	b.Init()
	if err := b.Parse(); err != nil {
		return nil, err
	}
	b.Execute()
	if b.parseStack.Peek() == nil {
		// the statement was parsed ok, but not put on the stack?
		// this should never occur.
		return nil, fmt.Errorf("no valid BQL statement could be parsed")
	}
	// pop it from the parse stack
	return b.parseStack.Pop().comp, nil
}
<|endoftext|>


<commit_before>/*
 Brassica is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 brassica/brassica-serve contains a command to start a httpd.
*/
package brassica

import (
	"fmt"
	"github.com/hoisie/mustache"
	"io/ioutil"
	"launchpad.net/goyaml"
	"net/http"
	"os"
	"path/filepath"
)

// Settings for the application and the site.
type Settings struct {
	// Path to the data directory.
	Root string

	// Path to the template directory.
	Templates string

	// Path to the static files.
	Statics string

	// Path to the site specific static files.
	SiteStatics string
}

// GetSettings returns application and site settings.
func GetSettings() Settings {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	settings := Settings{
		Root:        wd,
		Templates:   filepath.Join(filepath.Dir(wd), "templates"),
		Statics:     filepath.Join(filepath.Dir(wd), "static"),
		SiteStatics: filepath.Join(filepath.Dir(wd), "site-static")}
	return settings
}

type masterTmplEnv struct {
	Node                     Node
	BelowHeader              string
	Footer                   string
	PrimaryNav, SecondaryNav []navLink
}

// Renderer represents a template renderer.
type Renderer interface {
	// RenderInMaster renders the named template with the given context
	// and master template environment in the master template.
	RenderInMaster(name string, context map[string]string,
		env *masterTmplEnv) string
}

type renderer struct {
	// Root is the absolute path to the template directory.
	Root string
	// MasterTemplate holds the parsed master template.
	MasterTemplate *mustache.Template
}

// Render renders the named template with given context.
func (r renderer) Render(name string, context map[string]string) string {
	path := filepath.Join(r.Root, name)
	content := mustache.RenderFile(path, context)
	return content
}

// NewRenderer returns a new Renderer.
//
// root is the absolute path to the template directory.
func NewRenderer(root string) Renderer {
	var r renderer
	r.Root = root
	path := filepath.Join(r.Root, "master.html")
	tmpl, err := mustache.ParseFile(path)
	r.MasterTemplate = tmpl
	if err != nil {
		panic("Could not load master template.")
	}
	return r
}

func (r renderer) RenderInMaster(name string, context map[string]string,
	env *masterTmplEnv) string {
	content := r.Render(name, context)
	showSidebar := len(env.SecondaryNav) > 0
	return r.MasterTemplate.Render(env, map[string]interface{}{
		"Content":     content,
		"ShowSidebar": showSidebar})
}

// navLink represents a link in the navigation.
type navLink struct {
	Name, Target string
	Active       bool
}

// getNav returns the navigation for the given node.
//
// node is the path of the node for which to get the navigation.
// active is the currently active node.
// root is the path of the data directory.
//
// The keys of the returned map are the link titles, the values are
// the link targets.
func getNav(node, active, root string) []navLink {
	path := filepath.Join(root, node, "navigation.yaml")
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil
	}
	var navLinks []navLink
	goyaml.Unmarshal(content, &navLinks)
	for i, link := range navLinks {
		if link.Target == active {
			navLinks[i].Active = true
			break
		}
	}
	return navLinks
}

// Node is the interface implemented by the various node types
// (Documents, Images, ...).
type Node interface {
	// Path returns the node's path (e.g. "/node").
	Path() string

	// Title returns the node's title.
	Title() string

	// Description returns the node's description.
	Description() string

	// Get handles a GET request on the node.
	Get(w http.ResponseWriter, r *http.Request, renderer Renderer,
		settings Settings)

	// Post handles a POST request on the node.
	Post(w http.ResponseWriter, r *http.Request, renderer Renderer,
		settings Settings)
}

// node is the base implementation for nodes.
type node struct {
	path string
	data nodeData
}

type nodeData struct {
	Description string
	Title       string
	Type        string
}

func (n node) Path() string {
	return n.path
}

func (n node) Title() string {
	return n.data.Title
}

func (n node) Description() string {
	return n.data.Description
}

// Document is a node consisting of a html body.
type Document struct {
	node
	Body string
}

func (n Document) Get(w http.ResponseWriter, r *http.Request,
	renderer Renderer, settings Settings) {
	prinav := getNav("/", n.Path(), settings.Root)
	var secnav []navLink = nil
	if n.Path() != "/" {
		secnav = getNav(n.Path(), n.Path(), settings.Root)
	}
	env := masterTmplEnv{
		Node:         n,
		PrimaryNav:   prinav,
		SecondaryNav: secnav,
		Footer:       "The footer",
		BelowHeader:  "Below header"}
	content := renderer.RenderInMaster("view/document.html",
		map[string]string{"body": n.Body}, &env)
	fmt.Fprint(w, content)
}

func (n Document) Post(w http.ResponseWriter, r *http.Request,
	renderer Renderer, settings Settings) {
	http.Error(w, "Implementation missing.", http.StatusInternalServerError)
}

// NodeFile is the filename of node description files.
const NodeFile = "node.yaml"

// lookup_node look ups a node at the given path.
// If no such node exists, return nil.
func LookupNode(root, path string) (Node, error) {
	node_path := filepath.Join(root, path[1:], NodeFile)
	content, err := ioutil.ReadFile(node_path)
	if err != nil {
		return nil, err
	}
	var node = new(Document)
	body_path := filepath.Join(root, path[1:], "body.html")
	body, err := ioutil.ReadFile(body_path)
	if err != nil {
		panic("Body not found: " + body_path)
	}
	node.Body = string(body)
	var data nodeData
	goyaml.Unmarshal(content, &data)
	node.data = data
	node.path = path
	return node, nil
}
<commit_msg>Add comment.<commit_after>/*
 Brassica is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 brassica/brassica-serve contains a command to start a httpd.
*/
package brassica

import (
	"fmt"
	"github.com/hoisie/mustache"
	"io/ioutil"
	"launchpad.net/goyaml"
	"net/http"
	"os"
	"path/filepath"
)

// Settings for the application and the site.
type Settings struct {
	// Path to the data directory.
	Root string

	// Path to the template directory.
	Templates string

	// Path to the static files.
	Statics string

	// Path to the site specific static files.
	SiteStatics string
}

// GetSettings returns application and site settings.
func GetSettings() Settings {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	settings := Settings{
		Root:        wd,
		Templates:   filepath.Join(filepath.Dir(wd), "templates"),
		Statics:     filepath.Join(filepath.Dir(wd), "static"),
		SiteStatics: filepath.Join(filepath.Dir(wd), "site-static")}
	return settings
}

type masterTmplEnv struct {
	Node                     Node
	BelowHeader              string
	Footer                   string
	PrimaryNav, SecondaryNav []navLink
}

// Renderer represents a template renderer.
type Renderer interface {
	// RenderInMaster renders the named template with the given context
	// and master template environment in the master template.
	RenderInMaster(name string, context map[string]string,
		env *masterTmplEnv) string
}

type renderer struct {
	// Root is the absolute path to the template directory.
	Root string
	// MasterTemplate holds the parsed master template.
	MasterTemplate *mustache.Template
}

// Render renders the named template with given context.
func (r renderer) Render(name string, context map[string]string) string {
	path := filepath.Join(r.Root, name)
	content := mustache.RenderFile(path, context)
	return content
}

// NewRenderer returns a new Renderer.
//
// root is the absolute path to the template directory.
func NewRenderer(root string) Renderer {
	var r renderer
	r.Root = root
	path := filepath.Join(r.Root, "master.html")
	tmpl, err := mustache.ParseFile(path)
	r.MasterTemplate = tmpl
	if err != nil {
		panic("Could not load master template.")
	}
	return r
}

func (r renderer) RenderInMaster(name string, context map[string]string,
	env *masterTmplEnv) string {
	content := r.Render(name, context)
	showSidebar := len(env.SecondaryNav) > 0
	return r.MasterTemplate.Render(env, map[string]interface{}{
		"Content":     content,
		"ShowSidebar": showSidebar})
}

// navLink represents a link in the navigation.
type navLink struct {
	Name, Target string
	Active       bool
}

// getNav returns the navigation for the given node.
//
// node is the path of the node for which to get the navigation.
// active is the currently active node.
// root is the path of the data directory.
//
// The keys of the returned map are the link titles, the values are
// the link targets.
func getNav(node, active, root string) []navLink {
	path := filepath.Join(root, node, "navigation.yaml")
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil
	}
	var navLinks []navLink
	goyaml.Unmarshal(content, &navLinks)
	for i, link := range navLinks {
		if link.Target == active {
			navLinks[i].Active = true
			break
		}
	}
	return navLinks
}

// Node is the interface implemented by the various node types
// (Documents, Images, ...).
type Node interface {
	// Path returns the node's path (e.g. "/node").
	Path() string

	// Title returns the node's title.
	Title() string

	// Description returns the node's description.
	Description() string

	// Get handles a GET request on the node.
	Get(w http.ResponseWriter, r *http.Request, renderer Renderer,
		settings Settings)

	// Post handles a POST request on the node.
	Post(w http.ResponseWriter, r *http.Request, renderer Renderer,
		settings Settings)
}

// node is the base implementation for nodes.
type node struct {
	path string
	data nodeData
}

// nodeData is used for (un)marshaling from/to node.yaml.
type nodeData struct {
	Description string
	Title       string
	Type        string
}

func (n node) Path() string {
	return n.path
}

func (n node) Title() string {
	return n.data.Title
}

func (n node) Description() string {
	return n.data.Description
}

// Document is a node consisting of a html body.
type Document struct {
	node
	Body string
}

func (n Document) Get(w http.ResponseWriter, r *http.Request,
	renderer Renderer, settings Settings) {
	prinav := getNav("/", n.Path(), settings.Root)
	var secnav []navLink = nil
	if n.Path() != "/" {
		secnav = getNav(n.Path(), n.Path(), settings.Root)
	}
	env := masterTmplEnv{
		Node:         n,
		PrimaryNav:   prinav,
		SecondaryNav: secnav,
		Footer:       "The footer",
		BelowHeader:  "Below header"}
	content := renderer.RenderInMaster("view/document.html",
		map[string]string{"body": n.Body}, &env)
	fmt.Fprint(w, content)
}

func (n Document) Post(w http.ResponseWriter, r *http.Request,
	renderer Renderer, settings Settings) {
	http.Error(w, "Implementation missing.", http.StatusInternalServerError)
}

// NodeFile is the filename of node description files.
const NodeFile = "node.yaml"

// lookup_node look ups a node at the given path.
// If no such node exists, return nil.
func LookupNode(root, path string) (Node, error) {
	node_path := filepath.Join(root, path[1:], NodeFile)
	content, err := ioutil.ReadFile(node_path)
	if err != nil {
		return nil, err
	}
	var node = new(Document)
	body_path := filepath.Join(root, path[1:], "body.html")
	body, err := ioutil.ReadFile(body_path)
	if err != nil {
		panic("Body not found: " + body_path)
	}
	node.Body = string(body)
	var data nodeData
	goyaml.Unmarshal(content, &data)
	node.data = data
	node.path = path
	return node, nil
}
<|endoftext|>


<commit_before>package upload

import (
	"github.com/tidepool-org/platform/app"
	"github.com/tidepool-org/platform/data"
	"github.com/tidepool-org/platform/data/types/base"
)

type Deduplicator struct {
	Name string                 `bson:"name,omitempty"`
	Data map[string]interface{} `bson:"data,omitempty"`
}

type Upload struct {
	base.Base `bson:",inline"`

	DataState    string        `json:"-" bson:"_dataState,omitempty"`
	Deduplicator *Deduplicator `json:"-" bson:"_deduplicator,omitempty"`
	UploadUserID string        `json:"byUser,omitempty" bson:"byUser,omitempty"`

	ComputerTime        *string   `json:"computerTime,omitempty" bson:"computerTime,omitempty"`
	DeviceManufacturers *[]string `json:"deviceManufacturers,omitempty" bson:"deviceManufacturers,omitempty"`
	DeviceModel         *string   `json:"deviceModel,omitempty" bson:"deviceModel,omitempty"`
	DeviceSerialNumber  *string   `json:"deviceSerialNumber,omitempty" bson:"deviceSerialNumber,omitempty"`
	DeviceTags          *[]string `json:"deviceTags,omitempty" bson:"deviceTags,omitempty"`
	TimeProcessing      *string   `json:"timeProcessing,omitempty" bson:"timeProcessing,omitempty"`
	TimeZone            *string   `json:"timezone,omitempty" bson:"timezone,omitempty"`
	Version             *string   `json:"version,omitempty" bson:"version,omitempty"`
}

func Type() string {
	return "upload"
}

func NewDatum() data.Datum {
	return New()
}

func New() *Upload {
	return &Upload{}
}

func Init() *Upload {
	upload := New()
	upload.Init()
	return upload
}

func (u *Upload) Init() {
	u.Base.Init()
	u.Base.Type = Type()
	u.Base.UploadID = app.NewID()

	u.DataState = "open"
	u.Deduplicator = nil
	u.UploadUserID = ""

	u.ComputerTime = nil
	u.DeviceManufacturers = nil
	u.DeviceModel = nil
	u.DeviceSerialNumber = nil
	u.DeviceTags = nil
	u.TimeProcessing = nil
	u.TimeZone = nil
	u.Version = nil
}

func (u *Upload) Parse(parser data.ObjectParser) error {
	parser.SetMeta(u.Meta())

	if err := u.Base.Parse(parser); err != nil {
		return err
	}

	u.Version = parser.ParseString("version")
	u.ComputerTime = parser.ParseString("computerTime")
	u.DeviceTags = parser.ParseStringArray("deviceTags")
	u.DeviceManufacturers = parser.ParseStringArray("deviceManufacturers")
	u.DeviceModel = parser.ParseString("deviceModel")
	u.DeviceSerialNumber = parser.ParseString("deviceSerialNumber")
	u.TimeProcessing = parser.ParseString("timeProcessing")
	u.TimeZone = parser.ParseString("timezone")

	return nil
}

func (u *Upload) Validate(validator data.Validator) error {
	validator.SetMeta(u.Meta())

	if err := u.Base.Validate(validator); err != nil {
		return err
	}

	validator.ValidateString("version", u.Version).Exists().LengthGreaterThan(5)
	validator.ValidateStringAsTime("computerTime", u.ComputerTime, "2006-01-02T15:04:05").Exists()
	validator.ValidateStringArray("deviceTags", u.DeviceTags).Exists().NotEmpty().EachOneOf([]string{"insulin-pump", "cgm", "bgm"})
	validator.ValidateStringArray("deviceManufacturers", u.DeviceManufacturers).Exists().NotEmpty()
	validator.ValidateString("deviceModel", u.DeviceModel).Exists().LengthGreaterThan(1)
	validator.ValidateString("deviceSerialNumber", u.DeviceSerialNumber).Exists().LengthGreaterThan(1)
	validator.ValidateString("timeProcessing", u.TimeProcessing).Exists().OneOf([]string{"across-the-board-timezone", "utc-bootstrapping", "none"})
	validator.ValidateString("timezone", u.TimeZone).Exists().LengthGreaterThan(1)

	return nil
}

func (u *Upload) Normalize(normalizer data.Normalizer) error {
	normalizer.SetMeta(u.Meta())

	return u.Base.Normalize(normalizer)
}

func (u *Upload) SetUploadUserID(uploadUserID string) {
	u.UploadUserID = uploadUserID
}

func (u *Upload) SetDataState(dataState string) {
	u.DataState = dataState
}

func (u *Upload) SetDeduplicator(deduplicator *Deduplicator) {
	u.Deduplicator = deduplicator
}
<commit_msg>Sort by field names in upload datum<commit_after>package upload

import (
	"github.com/tidepool-org/platform/app"
	"github.com/tidepool-org/platform/data"
	"github.com/tidepool-org/platform/data/types/base"
)

type Deduplicator struct {
	Name string                 `bson:"name,omitempty"`
	Data map[string]interface{} `bson:"data,omitempty"`
}

type Upload struct {
	base.Base `bson:",inline"`

	DataState    string        `json:"-" bson:"_dataState,omitempty"`
	Deduplicator *Deduplicator `json:"-" bson:"_deduplicator,omitempty"`
	UploadUserID string        `json:"byUser,omitempty" bson:"byUser,omitempty"`

	ComputerTime        *string   `json:"computerTime,omitempty" bson:"computerTime,omitempty"`
	DeviceManufacturers *[]string `json:"deviceManufacturers,omitempty" bson:"deviceManufacturers,omitempty"`
	DeviceModel         *string   `json:"deviceModel,omitempty" bson:"deviceModel,omitempty"`
	DeviceSerialNumber  *string   `json:"deviceSerialNumber,omitempty" bson:"deviceSerialNumber,omitempty"`
	DeviceTags          *[]string `json:"deviceTags,omitempty" bson:"deviceTags,omitempty"`
	TimeProcessing      *string   `json:"timeProcessing,omitempty" bson:"timeProcessing,omitempty"`
	TimeZone            *string   `json:"timezone,omitempty" bson:"timezone,omitempty"`
	Version             *string   `json:"version,omitempty" bson:"version,omitempty"`
}

func Type() string {
	return "upload"
}

func NewDatum() data.Datum {
	return New()
}

func New() *Upload {
	return &Upload{}
}

func Init() *Upload {
	upload := New()
	upload.Init()
	return upload
}

func (u *Upload) Init() {
	u.Base.Init()
	u.Base.Type = Type()
	u.Base.UploadID = app.NewID()

	u.DataState = "open"
	u.Deduplicator = nil
	u.UploadUserID = ""

	u.ComputerTime = nil
	u.DeviceManufacturers = nil
	u.DeviceModel = nil
	u.DeviceSerialNumber = nil
	u.DeviceTags = nil
	u.TimeProcessing = nil
	u.TimeZone = nil
	u.Version = nil
}

func (u *Upload) Parse(parser data.ObjectParser) error {
	parser.SetMeta(u.Meta())

	if err := u.Base.Parse(parser); err != nil {
		return err
	}

	u.ComputerTime = parser.ParseString("computerTime")
	u.DeviceManufacturers = parser.ParseStringArray("deviceManufacturers")
	u.DeviceModel = parser.ParseString("deviceModel")
	u.DeviceSerialNumber = parser.ParseString("deviceSerialNumber")
	u.DeviceTags = parser.ParseStringArray("deviceTags")
	u.TimeProcessing = parser.ParseString("timeProcessing")
	u.TimeZone = parser.ParseString("timezone")
	u.Version = parser.ParseString("version")

	return nil
}

func (u *Upload) Validate(validator data.Validator) error {
	validator.SetMeta(u.Meta())

	if err := u.Base.Validate(validator); err != nil {
		return err
	}

	validator.ValidateStringAsTime("computerTime", u.ComputerTime, "2006-01-02T15:04:05").Exists()
	validator.ValidateStringArray("deviceManufacturers", u.DeviceManufacturers).Exists().NotEmpty()
	validator.ValidateString("deviceModel", u.DeviceModel).Exists().LengthGreaterThan(1)
	validator.ValidateString("deviceSerialNumber", u.DeviceSerialNumber).Exists().LengthGreaterThan(1)
	validator.ValidateStringArray("deviceTags", u.DeviceTags).Exists().NotEmpty().EachOneOf([]string{"insulin-pump", "cgm", "bgm"})
	validator.ValidateString("timeProcessing", u.TimeProcessing).Exists().OneOf([]string{"across-the-board-timezone", "utc-bootstrapping", "none"})
	validator.ValidateString("timezone", u.TimeZone).Exists().LengthGreaterThan(1)
	validator.ValidateString("version", u.Version).Exists().LengthGreaterThan(5)

	return nil
}

func (u *Upload) Normalize(normalizer data.Normalizer) error {
	normalizer.SetMeta(u.Meta())

	return u.Base.Normalize(normalizer)
}

func (u *Upload) SetUploadUserID(uploadUserID string) {
	u.UploadUserID = uploadUserID
}

func (u *Upload) SetDataState(dataState string) {
	u.DataState = dataState
}

func (u *Upload) SetDeduplicator(deduplicator *Deduplicator) {
	u.Deduplicator = deduplicator
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/base64"
	"encoding/json"
	"strings"

	"github.com/astaxie/beego"
	"github.com/lfq7413/tomato/client"
	"github.com/lfq7413/tomato/config"
	"github.com/lfq7413/tomato/errs"
	"github.com/lfq7413/tomato/rest"
	"github.com/lfq7413/tomato/types"
	"github.com/lfq7413/tomato/utils"
)

// BaseController ...
// Info 当前请求的权限信息
// Auth 当前请求的用户权限
// JSONBody 由 JSON 格式转换来的请求数据
// RawBody 原始请求数据
type BaseController struct {
	beego.Controller
	Info     *RequestInfo
	Auth     *rest.Auth
	Query    map[string]string
	JSONBody types.M
	RawBody  []byte
}

// RequestInfo http 请求的权限信息
type RequestInfo struct {
	AppID          string
	MasterKey      string
	ClientKey      string
	JavascriptKey  string
	DotNetKey      string
	RestAPIKey     string
	SessionToken   string
	InstallationID string
	ClientVersion  string
	ClientSDK      map[string]string
}

// Prepare 对请求权限进行处理
// 1. 从请求头中获取各种 key
// 2. 尝试按 json 格式转换 body
// 3. 尝试从 body 中获取各种 key
// 4. 校验请求权限
// 5. 生成用户信息
func (b *BaseController) Prepare() {
	info := &RequestInfo{}
	info.AppID = b.Ctx.Input.Header("X-Parse-Application-Id")
	info.MasterKey = b.Ctx.Input.Header("X-Parse-Master-Key")
	info.ClientKey = b.Ctx.Input.Header("X-Parse-Client-Key")
	info.JavascriptKey = b.Ctx.Input.Header("X-Parse-Javascript-Key")
	info.DotNetKey = b.Ctx.Input.Header("X-Parse-Windows-Key")
	info.RestAPIKey = b.Ctx.Input.Header("X-Parse-REST-API-Key")
	info.SessionToken = b.Ctx.Input.Header("X-Parse-Session-Token")
	info.InstallationID = b.Ctx.Input.Header("X-Parse-Installation-Id")
	info.ClientVersion = b.Ctx.Input.Header("X-Parse-Client-Version")

	basicAuth := httpAuth(b.Ctx.Input.Header("Authorization"))
	if basicAuth != nil {
		info.AppID = basicAuth["appId"]
		if basicAuth["masterKey"] != "" {
			info.MasterKey = basicAuth["masterKey"]
		}
		if basicAuth["javascriptKey"] != "" {
			info.ClientKey = basicAuth["javascriptKey"]
		}
	}

	b.Query = map[string]string{}
	input := b.Input()
	for key := range input {
		b.Query[key] = input.Get(key)
	}

	if b.Ctx.Input.RequestBody != nil {
		contentType := b.Ctx.Input.Header("Content-type")
		if strings.HasPrefix(contentType, "application/json") {
			// 请求数据为 json 格式，进行转换，转换出错则返回错误
			var object types.M
			err := json.Unmarshal(b.Ctx.Input.RequestBody, &object)
			if err != nil {
				b.HandleError(errs.E(errs.InvalidJSON, "invalid JSON"), 0)
				return
			}
			b.JSONBody = object
		} else {
			// 当 AppID 不存在时，尝试转换，转换失败不返回错误
			if info.AppID == "" {
				var object types.M
				err := json.Unmarshal(b.Ctx.Input.RequestBody, &object)
				if err == nil {
					b.JSONBody = object
				}
			}
		}
	}

	if b.JSONBody != nil {
		// Unity SDK sends a _noBody key which needs to be removed.
		// Unclear at this point if action needs to be taken.
		delete(b.JSONBody, "_noBody")
	}

	if info.AppID == "" {
		if b.JSONBody != nil {
			delete(b.JSONBody, "_RevocableSession")
		}
		// 从请求数据中获取各种 key
		if b.JSONBody != nil && b.JSONBody["_ApplicationId"] != nil {
			info.AppID = utils.S(b.JSONBody["_ApplicationId"])
			info.JavascriptKey = utils.S(b.JSONBody["_JavaScriptKey"])
			delete(b.JSONBody, "_ApplicationId")
			delete(b.JSONBody, "_JavaScriptKey")

			if b.JSONBody["_ClientVersion"] != nil {
				info.ClientVersion = utils.S(b.JSONBody["_ClientVersion"])
				delete(b.JSONBody, "_ClientVersion")
			}
			if b.JSONBody["_InstallationId"] != nil {
				info.InstallationID = utils.S(b.JSONBody["_InstallationId"])
				delete(b.JSONBody, "_InstallationId")
			}
			if b.JSONBody["_SessionToken"] != nil {
				info.SessionToken = utils.S(b.JSONBody["_SessionToken"])
				delete(b.JSONBody, "_SessionToken")
			}
			if b.JSONBody["_MasterKey"] != nil {
				info.MasterKey = utils.S(b.JSONBody["_MasterKey"])
				delete(b.JSONBody, "_MasterKey")
			}
			if b.JSONBody["_ContentType"] != nil {
				b.Ctx.Input.Context.Request.Header.Set("Content-type", utils.S(b.JSONBody["_ContentType"]))
				delete(b.JSONBody, "_ContentType")
			}
		} else {
			// 请求数据中也不存在 APPID 时，返回错误
			b.InvalidRequest()
			return
		}
	}

	if info.ClientVersion != "" {
		info.ClientSDK = client.FromString(info.ClientVersion)
	}

	b.Info = info

	// 校验请求权限
	if info.AppID != config.TConfig.AppID {
		b.InvalidRequest()
		return
	}
	if info.MasterKey == config.TConfig.MasterKey {
		b.Auth = &rest.Auth{InstallationID: info.InstallationID, IsMaster: true}
		return
	}
	var allow = false
	if (len(info.ClientKey) > 0 && info.ClientKey == config.TConfig.ClientKey) ||
		(len(info.JavascriptKey) > 0 && info.JavascriptKey == config.TConfig.JavascriptKey) ||
		(len(info.RestAPIKey) > 0 && info.RestAPIKey == config.TConfig.RestAPIKey) ||
		(len(info.DotNetKey) > 0 && info.DotNetKey == config.TConfig.DotNetKey) {
		allow = true
	}
	if allow == false {
		b.InvalidRequest()
		return
	}
	// TODO 登录时删除 Token ，如何处理接口地址？
	url := b.Ctx.Input.URL()
	if url == "/v1/login" || url == "/v1/login/" {
		info.SessionToken = ""
	}
	// 生成当前会话用户权限信息
	if info.SessionToken == "" {
		b.Auth = &rest.Auth{InstallationID: info.InstallationID, IsMaster: false}
	} else {
		var err error
		b.Auth, err = rest.GetAuthForSessionToken(info.SessionToken, info.InstallationID)
		if err != nil {
			b.HandleError(err, 0)
			return
		}
	}
}

func httpAuth(authorization string) map[string]string {
	if authorization == "" {
		return nil
	}

	var appID, masterKey, javascriptKey string
	authPrefix1 := "basic "
	authPrefix2 := "basic "

	match := strings.HasPrefix(authorization, authPrefix1) || strings.HasPrefix(authorization, authPrefix2)
	if match {
		encodedAuth := authorization[len(authPrefix1):]
		credentials := strings.Split(decodeBase64(encodedAuth), ":")

		if len(credentials) == 2 {
			appID = credentials[0]
			key := credentials[1]
			jsKeyPrefix := "javascript-key="

			matchKey := strings.HasPrefix(key, jsKeyPrefix)
			if matchKey {
				javascriptKey = key[len(jsKeyPrefix):]
			} else {
				masterKey = key
			}
			return map[string]string{
				"appId":         appID,
				"masterKey":     masterKey,
				"javascriptKey": javascriptKey,
			}
		}
		return nil
	}

	return nil
}

func decodeBase64(str string) string {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return ""
	}
	return string(data)
}

// HandleError 返回错误信息，不指定 status 参数时，默认为 0
func (b *BaseController) HandleError(err error, status int) {
	code := errs.GetErrorCode(err)
	if code != 0 {
		var httpStatus int
		switch code {
		case errs.InternalServerError:
			httpStatus = 500
		case errs.ObjectNotFound:
			httpStatus = 404
		default:
			httpStatus = 400
		}

		b.Ctx.Output.SetStatus(httpStatus)
		b.Data["json"] = errs.ErrorToMap(err)
		b.ServeJSON()
		return
	}

	if status != 0 {
		b.Ctx.Output.SetStatus(status)
		b.Data["json"] = types.M{"error": err.Error()}
		b.ServeJSON()
		return
	}

	b.Ctx.Output.SetStatus(500)
	b.Data["json"] = errs.ErrorMessageToMap(errs.InternalServerError, "Internal server error: "+err.Error())
	b.ServeJSON()
}

// InvalidRequest 无效请求
func (b *BaseController) InvalidRequest() {
	b.Ctx.Output.SetStatus(403)
	b.Data["json"] = types.M{"error": "unauthorized"}
	b.ServeJSON()
}
<commit_msg>添加 Master 权限校验功能<commit_after>package controllers

import (
	"encoding/base64"
	"encoding/json"
	"strings"

	"github.com/astaxie/beego"
	"github.com/lfq7413/tomato/client"
	"github.com/lfq7413/tomato/config"
	"github.com/lfq7413/tomato/errs"
	"github.com/lfq7413/tomato/rest"
	"github.com/lfq7413/tomato/types"
	"github.com/lfq7413/tomato/utils"
)

// BaseController ...
// Info 当前请求的权限信息
// Auth 当前请求的用户权限
// JSONBody 由 JSON 格式转换来的请求数据
// RawBody 原始请求数据
type BaseController struct {
	beego.Controller
	Info     *RequestInfo
	Auth     *rest.Auth
	Query    map[string]string
	JSONBody types.M
	RawBody  []byte
}

// RequestInfo http 请求的权限信息
type RequestInfo struct {
	AppID          string
	MasterKey      string
	ClientKey      string
	JavascriptKey  string
	DotNetKey      string
	RestAPIKey     string
	SessionToken   string
	InstallationID string
	ClientVersion  string
	ClientSDK      map[string]string
}

// Prepare 对请求权限进行处理
// 1. 从请求头中获取各种 key
// 2. 尝试按 json 格式转换 body
// 3. 尝试从 body 中获取各种 key
// 4. 校验请求权限
// 5. 生成用户信息
func (b *BaseController) Prepare() {
	info := &RequestInfo{}
	info.AppID = b.Ctx.Input.Header("X-Parse-Application-Id")
	info.MasterKey = b.Ctx.Input.Header("X-Parse-Master-Key")
	info.ClientKey = b.Ctx.Input.Header("X-Parse-Client-Key")
	info.JavascriptKey = b.Ctx.Input.Header("X-Parse-Javascript-Key")
	info.DotNetKey = b.Ctx.Input.Header("X-Parse-Windows-Key")
	info.RestAPIKey = b.Ctx.Input.Header("X-Parse-REST-API-Key")
	info.SessionToken = b.Ctx.Input.Header("X-Parse-Session-Token")
	info.InstallationID = b.Ctx.Input.Header("X-Parse-Installation-Id")
	info.ClientVersion = b.Ctx.Input.Header("X-Parse-Client-Version")

	basicAuth := httpAuth(b.Ctx.Input.Header("Authorization"))
	if basicAuth != nil {
		info.AppID = basicAuth["appId"]
		if basicAuth["masterKey"] != "" {
			info.MasterKey = basicAuth["masterKey"]
		}
		if basicAuth["javascriptKey"] != "" {
			info.ClientKey = basicAuth["javascriptKey"]
		}
	}

	b.Query = map[string]string{}
	input := b.Input()
	for key := range input {
		b.Query[key] = input.Get(key)
	}

	if b.Ctx.Input.RequestBody != nil {
		contentType := b.Ctx.Input.Header("Content-type")
		if strings.HasPrefix(contentType, "application/json") {
			// 请求数据为 json 格式，进行转换，转换出错则返回错误
			var object types.M
			err := json.Unmarshal(b.Ctx.Input.RequestBody, &object)
			if err != nil {
				b.HandleError(errs.E(errs.InvalidJSON, "invalid JSON"), 0)
				return
			}
			b.JSONBody = object
		} else {
			// 当 AppID 不存在时，尝试转换，转换失败不返回错误
			if info.AppID == "" {
				var object types.M
				err := json.Unmarshal(b.Ctx.Input.RequestBody, &object)
				if err == nil {
					b.JSONBody = object
				}
			}
		}
	}

	if b.JSONBody != nil {
		// Unity SDK sends a _noBody key which needs to be removed.
		// Unclear at this point if action needs to be taken.
		delete(b.JSONBody, "_noBody")
	}

	if info.AppID == "" {
		if b.JSONBody != nil {
			delete(b.JSONBody, "_RevocableSession")
		}
		// 从请求数据中获取各种 key
		if b.JSONBody != nil && b.JSONBody["_ApplicationId"] != nil {
			info.AppID = utils.S(b.JSONBody["_ApplicationId"])
			info.JavascriptKey = utils.S(b.JSONBody["_JavaScriptKey"])
			delete(b.JSONBody, "_ApplicationId")
			delete(b.JSONBody, "_JavaScriptKey")

			if b.JSONBody["_ClientVersion"] != nil {
				info.ClientVersion = utils.S(b.JSONBody["_ClientVersion"])
				delete(b.JSONBody, "_ClientVersion")
			}
			if b.JSONBody["_InstallationId"] != nil {
				info.InstallationID = utils.S(b.JSONBody["_InstallationId"])
				delete(b.JSONBody, "_InstallationId")
			}
			if b.JSONBody["_SessionToken"] != nil {
				info.SessionToken = utils.S(b.JSONBody["_SessionToken"])
				delete(b.JSONBody, "_SessionToken")
			}
			if b.JSONBody["_MasterKey"] != nil {
				info.MasterKey = utils.S(b.JSONBody["_MasterKey"])
				delete(b.JSONBody, "_MasterKey")
			}
			if b.JSONBody["_ContentType"] != nil {
				b.Ctx.Input.Context.Request.Header.Set("Content-type", utils.S(b.JSONBody["_ContentType"]))
				delete(b.JSONBody, "_ContentType")
			}
		} else {
			// 请求数据中也不存在 APPID 时，返回错误
			b.InvalidRequest()
			return
		}
	}

	if info.ClientVersion != "" {
		info.ClientSDK = client.FromString(info.ClientVersion)
	}

	b.Info = info

	// 校验请求权限
	if info.AppID != config.TConfig.AppID {
		b.InvalidRequest()
		return
	}
	if info.MasterKey == config.TConfig.MasterKey {
		b.Auth = &rest.Auth{InstallationID: info.InstallationID, IsMaster: true}
		return
	}
	var allow = false
	if (len(info.ClientKey) > 0 && info.ClientKey == config.TConfig.ClientKey) ||
		(len(info.JavascriptKey) > 0 && info.JavascriptKey == config.TConfig.JavascriptKey) ||
		(len(info.RestAPIKey) > 0 && info.RestAPIKey == config.TConfig.RestAPIKey) ||
		(len(info.DotNetKey) > 0 && info.DotNetKey == config.TConfig.DotNetKey) {
		allow = true
	}
	if allow == false {
		b.InvalidRequest()
		return
	}
	// TODO 登录时删除 Token ，如何处理接口地址？
	url := b.Ctx.Input.URL()
	if url == "/v1/login" || url == "/v1/login/" {
		info.SessionToken = ""
	}
	// 生成当前会话用户权限信息
	if info.SessionToken == "" {
		b.Auth = &rest.Auth{InstallationID: info.InstallationID, IsMaster: false}
	} else {
		var err error
		b.Auth, err = rest.GetAuthForSessionToken(info.SessionToken, info.InstallationID)
		if err != nil {
			b.HandleError(err, 0)
			return
		}
	}
}

func httpAuth(authorization string) map[string]string {
	if authorization == "" {
		return nil
	}

	var appID, masterKey, javascriptKey string
	authPrefix1 := "basic "
	authPrefix2 := "basic "

	match := strings.HasPrefix(authorization, authPrefix1) || strings.HasPrefix(authorization, authPrefix2)
	if match {
		encodedAuth := authorization[len(authPrefix1):]
		credentials := strings.Split(decodeBase64(encodedAuth), ":")

		if len(credentials) == 2 {
			appID = credentials[0]
			key := credentials[1]
			jsKeyPrefix := "javascript-key="

			matchKey := strings.HasPrefix(key, jsKeyPrefix)
			if matchKey {
				javascriptKey = key[len(jsKeyPrefix):]
			} else {
				masterKey = key
			}
			return map[string]string{
				"appId":         appID,
				"masterKey":     masterKey,
				"javascriptKey": javascriptKey,
			}
		}
		return nil
	}

	return nil
}

func decodeBase64(str string) string {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return ""
	}
	return string(data)
}

// HandleError 返回错误信息，不指定 status 参数时，默认为 0
func (b *BaseController) HandleError(err error, status int) {
	code := errs.GetErrorCode(err)
	if code != 0 {
		var httpStatus int
		switch code {
		case errs.InternalServerError:
			httpStatus = 500
		case errs.ObjectNotFound:
			httpStatus = 404
		default:
			httpStatus = 400
		}

		b.Ctx.Output.SetStatus(httpStatus)
		b.Data["json"] = errs.ErrorToMap(err)
		b.ServeJSON()
		return
	}

	if status != 0 {
		b.Ctx.Output.SetStatus(status)
		b.Data["json"] = types.M{"error": err.Error()}
		b.ServeJSON()
		return
	}

	b.Ctx.Output.SetStatus(500)
	b.Data["json"] = errs.ErrorMessageToMap(errs.InternalServerError, "Internal server error: "+err.Error())
	b.ServeJSON()
}

// InvalidRequest 无效请求
func (b *BaseController) InvalidRequest() {
	b.Ctx.Output.SetStatus(403)
	b.Data["json"] = types.M{"error": "unauthorized"}
	b.ServeJSON()
}

// EnforceMasterKeyAccess 接口需要 Master 权限
// 返回 true 表示当前请求是 Master 权限
func (b *BaseController) EnforceMasterKeyAccess() bool {
	if b.Auth.IsMaster == false {
		b.Ctx.Output.SetStatus(403)
		b.Data["json"] = types.M{"error": "unauthorized: master key is required"}
		b.ServeJSON()
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"

	"github.com/lifei6671/go-git-webhook/models"
	"github.com/lifei6671/go-git-webhook/conf"

	"github.com/astaxie/beego"
)

// BaseController 基础控制器
type BaseController struct {
	beego.Controller
	Member *models.Member
	Scheme string
}

// Prepare 预处理.
func (c *BaseController) Prepare (){
	c.Data["SiteName"] = "Git WebHook"
	c.Data["Member"] = models.Member{}

	if member,ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0{
		c.Member = &member
		c.Data["Member"] = c.Member
	}

	scheme := "http"

	if c.Ctx.Request.TLS != nil {
		scheme = "https"
	}
	c.Scheme = scheme
}

// SetMember 获取或设置当前登录用户信息,如果 MemberId 小于 0 则标识删除 Session
func (c *BaseController) SetMember(member models.Member) {

	if member.MemberId <= 0 {
		c.DelSession(conf.LoginSessionName)
		c.DelSession("uid")
		c.DestroySession()
	} else {
		c.SetSession(conf.LoginSessionName, member)
		c.SetSession("uid", member.MemberId)
	}
}

// JsonResult 响应 json 结果
func (c *BaseController) JsonResult(errCode int,errMsg string,data ...interface{}){
	json := make(map[string]interface{},3)

	json["errcode"] = errCode
	json["message"] = errMsg

	if len(data) > 0 && data[0] != nil{
		json["data"] = data[0]
	}

	c.Data["json"] = json
	c.ServeJSON(true)
	c.StopRun()
}

// UrlFor .
func (c *BaseController) UrlFor (endpoint string, values ...interface{}) string {

	return c.BaseUrl() + beego.URLFor(endpoint,values...)
}

// BaseUrl .
func (c *BaseController) BaseUrl() string {

	if baseUrl := beego.AppConfig.String("base_url"); baseUrl != "" {
		return baseUrl
	}
	scheme := "http://"

	if c.Ctx.Request.TLS != nil {
		scheme = "https://"
	}
	return scheme + c.Ctx.Request.Host
}

// NotFound .
func (c *BaseController) NotFound(message interface{})  {
	c.TplName = "errors/404.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// Forbidden .
func (c *BaseController) Forbidden(message interface{}) {
	c.TplName = "errors/403.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// ServerError .
func (c *BaseController) ServerError (message interface{}) {
	c.TplName = "errors/500.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// ExecuteViewPathTemplate 执行指定的模板并返回执行结果.
func (c *BaseController) ExecuteViewPathTemplate(tplName string,data interface{}) (string,error){
	var buf bytes.Buffer

	viewPath := c.ViewPath

	if c.ViewPath == "" {
		viewPath = beego.BConfig.WebConfig.ViewsPath

	}

	if err := beego.ExecuteViewPathTemplate(&buf,tplName,viewPath,data); err != nil {
		return "",err
	}
	return buf.String(),nil
}<commit_msg>使用框架内置方法判断http协议。<commit_after>package controllers

import (
	"bytes"

	"github.com/lifei6671/go-git-webhook/models"
	"github.com/lifei6671/go-git-webhook/conf"

	"github.com/astaxie/beego"
)

// BaseController 基础控制器
type BaseController struct {
	beego.Controller
	Member *models.Member
	Scheme string
}

// Prepare 预处理.
func (c *BaseController) Prepare (){
	c.Data["SiteName"] = "Git WebHook"
	c.Data["Member"] = models.Member{}

	if member,ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0{
		c.Member = &member
		c.Data["Member"] = c.Member
	}

	scheme := "http"

	if c.Ctx.Request.TLS != nil {
		scheme = "https"
	}
	c.Scheme = scheme
}

// SetMember 获取或设置当前登录用户信息,如果 MemberId 小于 0 则标识删除 Session
func (c *BaseController) SetMember(member models.Member) {

	if member.MemberId <= 0 {
		c.DelSession(conf.LoginSessionName)
		c.DelSession("uid")
		c.DestroySession()
	} else {
		c.SetSession(conf.LoginSessionName, member)
		c.SetSession("uid", member.MemberId)
	}
}

// JsonResult 响应 json 结果
func (c *BaseController) JsonResult(errCode int,errMsg string,data ...interface{}){
	json := make(map[string]interface{},3)

	json["errcode"] = errCode
	json["message"] = errMsg

	if len(data) > 0 && data[0] != nil{
		json["data"] = data[0]
	}

	c.Data["json"] = json
	c.ServeJSON(true)
	c.StopRun()
}

// UrlFor .
func (c *BaseController) UrlFor (endpoint string, values ...interface{}) string {

	return c.BaseUrl() + beego.URLFor(endpoint,values...)
}

// BaseUrl .
func (c *BaseController) BaseUrl() string {

	if baseUrl := beego.AppConfig.String("base_url"); baseUrl != "" {
		return baseUrl
	}

	return c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
}

// NotFound .
func (c *BaseController) NotFound(message interface{})  {
	c.TplName = "errors/404.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// Forbidden .
func (c *BaseController) Forbidden(message interface{}) {
	c.TplName = "errors/403.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// ServerError .
func (c *BaseController) ServerError (message interface{}) {
	c.TplName = "errors/500.html"
	c.Layout = ""
	c.Data["Model"] = map[string]interface{}{"Message":message}

	html,_ := c.RenderString()

	c.Abort(html)
}

// ExecuteViewPathTemplate 执行指定的模板并返回执行结果.
func (c *BaseController) ExecuteViewPathTemplate(tplName string,data interface{}) (string,error){
	var buf bytes.Buffer

	viewPath := c.ViewPath

	if c.ViewPath == "" {
		viewPath = beego.BConfig.WebConfig.ViewsPath

	}

	if err := beego.ExecuteViewPathTemplate(&buf,tplName,viewPath,data); err != nil {
		return "",err
	}
	return buf.String(),nil
}<|endoftext|>