<commit_before>package scipipe

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	re "regexp"
	str "strings"
)

type ShellProcess struct {
	process
	InPorts        map[string]chan *FileTarget
	OutPorts       map[string]chan *FileTarget
	OutPortsFifo   map[string]bool
	OutPathFuncs   map[string]func(*ShellTask) string
	ParamPorts     map[string]chan string
	Prepend        string
	CommandPattern string
	Spawn          bool
}

func NewShellProcess(command string) *ShellProcess {
	return &ShellProcess{
		CommandPattern: command,
		InPorts:        make(map[string]chan *FileTarget),
		OutPorts:       make(map[string]chan *FileTarget),
		OutPortsFifo:   make(map[string]bool),
		OutPathFuncs:   make(map[string]func(*ShellTask) string),
		ParamPorts:     make(map[string]chan string),
		Spawn:          true,
	}
}

func Shell(cmd string) *ShellProcess {
	if !LogExists {
		InitLogInfo()
	}
	p := NewShellProcess(cmd)
	p.initPortsFromCmdPattern(cmd, nil)
	return p
}

func Sh(cmd string) *ShellProcess {
	return Shell(cmd)
}

func (p *ShellProcess) Run() {
	defer p.closeOutPorts()

	tasks := []*ShellTask{}
	Debug.Printf("[%s] Starting to loop over tasks\n", p.CommandPattern)
	for t := range p.createTasks() {
		Debug.Println("Now processing task", t.Command, "...")
		tasks = append(tasks, t)
		// Send fifos here
		go t.Run()
	}

	// Wait for finish, and send out targets in arrival order
	for _, t := range tasks {
		Debug.Printf("[%s] Waiting for Done from task: %s\n", p.CommandPattern, t.Command)
		<-t.Done
		Debug.Printf("[%s] Receiving Done from task: %s\n", p.CommandPattern, t.Command)
		for oname, otgt := range t.OutTargets {
			Debug.Printf("[%s] Sent on outport %s ...\n", p.CommandPattern, oname)
			p.OutPorts[oname] <- otgt
		}
	}
}

func (p *ShellProcess) initPortsFromCmdPattern(cmd string, params map[string]string) {
	// Find in/out port names and Params and set up in struct fields
	r := getPlaceHolderRegex()
	ms := r.FindAllStringSubmatch(cmd, -1)
	for _, m := range ms {
		if len(m) < 3 {
			Check(errors.New("Too few matches"))
		}
		typ := m[1]
		name := m[2]
		if typ == "o" || typ == "os" {
			p.OutPorts[name] = make(chan *FileTarget, BUFSIZE)
			if typ == "os" {
				p.OutPortsFifo[name] = true
			}
		} else if typ == "i" {
			// Set up a channel on the inports, even though this is
			// often replaced by another processes output port channel.
			// It might be nice to have it init'ed with a channel
			// anyways, for use cases when we want to send FileTargets
			// on the inport manually.
			p.InPorts[name] = make(chan *FileTarget, BUFSIZE)
		} else if typ == "p" {
			if params == nil || params[name] == "" {
				p.ParamPorts[name] = make(chan string, BUFSIZE)
			}
		}
	}
}

func (p *ShellProcess) createTasks() (ch chan *ShellTask) {
	ch = make(chan *ShellTask)
	go func() {
		defer close(ch)
		for {
			inTargets, inPortsOpen := p.receiveInputs()
			Debug.Printf("[%s] Got inTargets: %s", p.CommandPattern, inTargets)
			params, paramPortsOpen := p.receiveParams()
			Debug.Printf("[%s] Got params: %s", p.CommandPattern, params)
			if !inPortsOpen && !paramPortsOpen {
				Debug.Printf("[%s] Breaking: Both inPorts and paramPorts closed", p.CommandPattern)
				break
			}
			if len(p.InPorts) == 0 && !paramPortsOpen {
				Debug.Printf("[%s] Breaking: No inports, and params closed", p.CommandPattern)
				break
			}
			if len(p.ParamPorts) == 0 && !inPortsOpen {
				Debug.Printf("[%s] Breaking: No params, and inPorts closed", p.CommandPattern)
				break
			}
			t := NewShellTask(p.CommandPattern, inTargets, p.OutPathFuncs, params, p.Prepend)
			ch <- t
			if len(p.InPorts) == 0 && len(p.ParamPorts) == 0 {
				Debug.Printf("[%s] Breaking: No inports nor params", p.CommandPattern)
				break
			}
		}
	}()
	return ch
}

func (p *ShellProcess) receiveInputs() (inTargets map[string]*FileTarget, inPortsOpen bool) {
	inPortsOpen = true
	inTargets = make(map[string]*FileTarget)
	// Read input targets on in-ports and set up path mappings
	for iname, ichan := range p.InPorts {
		Debug.Printf("[%s] Receieving on inPort %s ...", p.CommandPattern, iname)
		inTarget, open := <-ichan
		if !open {
			inPortsOpen = false
			continue
		}
		Debug.Printf("[%s] Got inTarget %s ...", p.CommandPattern, inTarget.GetPath())
		inTargets[iname] = inTarget
	}
	return
}

// func (p *ShellProcess) createOutTargets() (outTargets map[string]*FileTarget) {
// 	// Create out targets
// 	outTargets = make(map[string]*FileTarget)
// 	for oname, _ := range p.OutPorts {
// 		pathfun := p.OutPathFuncs[oname]
// 		outTargets[oname] = NewFileTarget(pathfun(t))
// 	}
// 	return
// }

func (p *ShellProcess) receiveParams() (params map[string]string, paramPortsOpen bool) {
	paramPortsOpen = true
	params = make(map[string]string)
	// Read input targets on in-ports and set up path mappings
	for pname, pchan := range p.ParamPorts {
		pval, open := <-pchan
		if !open {
			paramPortsOpen = false
			continue
		}
		Debug.Println("Receiving param:", pname, "with value", pval)
		params[pname] = pval
	}
	return
}

func (p *ShellProcess) closeOutPorts() {
	for oname, oport := range p.OutPorts {
		Debug.Printf("[%s] Closing port %s ...\n", p.CommandPattern, oname)
		close(oport)
	}
}

func getPlaceHolderRegex() *re.Regexp {
	r, err := re.Compile("{(o|os|i|is|p):([^{}:]+)}")
	Check(err)
	return r
}

// ------- ShellTask -------

type ShellTask struct {
	InTargets  map[string]*FileTarget
	OutTargets map[string]*FileTarget
	Params     map[string]string
	Command    string
	Done       chan int
}

func NewShellTask(cmdPat string, inTargets map[string]*FileTarget, outPathFuncs map[string]func(*ShellTask) string, params map[string]string, prepend string) *ShellTask {
	t := &ShellTask{
		InTargets:  inTargets,
		OutTargets: make(map[string]*FileTarget),
		Params:     params,
		Command:    "",
		Done:       make(chan int),
	}
	// Create out targets
	Debug.Printf("[%s] Creating outTargets now ...", cmdPat)
	outTargets := make(map[string]*FileTarget)
	for oname, ofun := range outPathFuncs {
		opath := ofun(t)
		Debug.Printf("[%s] Creating outTarget with path %s ...", cmdPat, opath)
		outTargets[oname] = NewFileTarget(opath)
	}
	t.OutTargets = outTargets
	t.Command = formatCommand(cmdPat, inTargets, outTargets, params, prepend)
	Debug.Printf("[%s] Created formatted command: %s", cmdPat, t.Command)
	return t
}

func (t *ShellTask) Run() {
	defer close(t.Done) // TODO: Is this needed?
	if !t.anyOutputExists() {
		t.executeCommand(t.Command)
		t.atomizeTargets()
	}
	Debug.Printf("[%s] Starting to send Done in t.Run() ...)\n", t.Command)
	t.Done <- 1
	Debug.Printf("[%s] Done sending Done, in t.Run()\n", t.Command)
}

func (t *ShellTask) executeCommand(cmd string) {
	Info.Printf("[%s] Executing command: %s \n", t.Command, cmd)
	_, err := exec.Command("bash", "-c", cmd).Output()
	Check(err)
}

func (t *ShellTask) GetInPath(inPort string) string {
	return t.InTargets[inPort].GetPath()
}

func formatCommand(cmd string, inTargets map[string]*FileTarget, outTargets map[string]*FileTarget, params map[string]string, prepend string) string {

	// Debug.Println("Formatting command with the following data:")
	// Debug.Println("prepend:", prepend)
	// Debug.Println("cmd:", cmd)
	// Debug.Println("inTargets:", inTargets)
	// Debug.Println("outTargets:", outTargets)
	// Debug.Println("params:", params)

	r := getPlaceHolderRegex()
	ms := r.FindAllStringSubmatch(cmd, -1)
	for _, m := range ms {
		whole := m[0]
		typ := m[1]
		name := m[2]
		var newstr string
		if typ == "o" || typ == "os" {
			if outTargets[name] == nil {
				msg := fmt.Sprint("Missing outpath for outport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				if typ == "o" {
					newstr = outTargets[name].GetTempPath() // Means important to Atomize afterwards!
				} else if typ == "os" {
					newstr = outTargets[name].GetFifoPath()
				}
			}
		} else if typ == "i" {
			if inTargets[name] == nil {
				msg := fmt.Sprint("Missing intarget for inport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else if inTargets[name].GetPath() == "" {
				msg := fmt.Sprint("Missing inpath for inport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				if typ == "i" {
					if inTargets[name].doStream {
						newstr = inTargets[name].GetFifoPath()
					} else {
						newstr = inTargets[name].GetPath()
					}
				}
			}
		} else if typ == "p" {
			if params[name] == "" {
				msg := fmt.Sprint("Missing param value param '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				newstr = params[name]
			}
		}
		if newstr == "" {
			msg := fmt.Sprint("Replace failed for port ", name, " forcommand '", cmd, "'")
			Check(errors.New(msg))
		}
		cmd = str.Replace(cmd, whole, newstr, -1)
	}
	// Add prepend string to the command
	if prepend != "" {
		cmd = fmt.Sprintf("%s %s", prepend, cmd)
	}
	return cmd
}

func (t *ShellTask) atomizeTargets() {
	for _, tgt := range t.OutTargets {
		if !tgt.doStream {
			Debug.Printf("Atomizing file: %s -> %s", tgt.GetTempPath(), tgt.GetPath())
			tgt.Atomize()
			Debug.Printf("Done atomizing file: %s -> %s", tgt.GetTempPath(), tgt.GetPath())
		} else {
			Debug.Printf("Target is streaming, so not atomizing: %s", tgt.GetPath())
		}
	}
}

func (t *ShellTask) anyOutputExists() (anyFileExists bool) {
	anyFileExists = false
	for _, tgt := range t.OutTargets {
		opath := tgt.GetPath()
		otmpPath := tgt.GetTempPath()
		ofifoPath := tgt.GetFifoPath()
		if _, err := os.Stat(opath); err == nil {
			Warn.Printf("[%s] Output file already exists: %s. Check your workflow for correctness!\n", t.Command, opath)
			anyFileExists = true
		}
		if _, err := os.Stat(otmpPath); err == nil {
			Warn.Printf("[%s] Temporary Output file already exists: %s. Check your workflow for correctness!\n", t.Command, otmpPath)
			anyFileExists = true
		}
		if _, err := os.Stat(ofifoPath); err == nil {
			Warn.Printf("[%s] FIFO Output file already exists: %s. Check your workflow for correctness!\n", t.Command, ofifoPath)
			anyFileExists = true
		}
	}
	return
}
<commit_msg>Clean up deprecated create outputs function<commit_after>package scipipe

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	re "regexp"
	str "strings"
)

type ShellProcess struct {
	process
	InPorts        map[string]chan *FileTarget
	OutPorts       map[string]chan *FileTarget
	OutPortsFifo   map[string]bool
	OutPathFuncs   map[string]func(*ShellTask) string
	ParamPorts     map[string]chan string
	Prepend        string
	CommandPattern string
	Spawn          bool
}

func NewShellProcess(command string) *ShellProcess {
	return &ShellProcess{
		CommandPattern: command,
		InPorts:        make(map[string]chan *FileTarget),
		OutPorts:       make(map[string]chan *FileTarget),
		OutPortsFifo:   make(map[string]bool),
		OutPathFuncs:   make(map[string]func(*ShellTask) string),
		ParamPorts:     make(map[string]chan string),
		Spawn:          true,
	}
}

func Shell(cmd string) *ShellProcess {
	if !LogExists {
		InitLogInfo()
	}
	p := NewShellProcess(cmd)
	p.initPortsFromCmdPattern(cmd, nil)
	return p
}

func Sh(cmd string) *ShellProcess {
	return Shell(cmd)
}

func (p *ShellProcess) Run() {
	defer p.closeOutPorts()

	tasks := []*ShellTask{}
	Debug.Printf("[%s] Starting to loop over tasks\n", p.CommandPattern)
	for t := range p.createTasks() {
		Debug.Println("Now processing task", t.Command, "...")
		tasks = append(tasks, t)
		// Send fifos here
		go t.Run()
	}

	// Wait for finish, and send out targets in arrival order
	for _, t := range tasks {
		Debug.Printf("[%s] Waiting for Done from task: %s\n", p.CommandPattern, t.Command)
		<-t.Done
		Debug.Printf("[%s] Receiving Done from task: %s\n", p.CommandPattern, t.Command)
		for oname, otgt := range t.OutTargets {
			Debug.Printf("[%s] Sent on outport %s ...\n", p.CommandPattern, oname)
			p.OutPorts[oname] <- otgt
		}
	}
}

func (p *ShellProcess) initPortsFromCmdPattern(cmd string, params map[string]string) {
	// Find in/out port names and Params and set up in struct fields
	r := getPlaceHolderRegex()
	ms := r.FindAllStringSubmatch(cmd, -1)
	for _, m := range ms {
		if len(m) < 3 {
			Check(errors.New("Too few matches"))
		}
		typ := m[1]
		name := m[2]
		if typ == "o" || typ == "os" {
			p.OutPorts[name] = make(chan *FileTarget, BUFSIZE)
			if typ == "os" {
				p.OutPortsFifo[name] = true
			}
		} else if typ == "i" {
			// Set up a channel on the inports, even though this is
			// often replaced by another processes output port channel.
			// It might be nice to have it init'ed with a channel
			// anyways, for use cases when we want to send FileTargets
			// on the inport manually.
			p.InPorts[name] = make(chan *FileTarget, BUFSIZE)
		} else if typ == "p" {
			if params == nil || params[name] == "" {
				p.ParamPorts[name] = make(chan string, BUFSIZE)
			}
		}
	}
}

func (p *ShellProcess) createTasks() (ch chan *ShellTask) {
	ch = make(chan *ShellTask)
	go func() {
		defer close(ch)
		for {
			inTargets, inPortsOpen := p.receiveInputs()
			Debug.Printf("[%s] Got inTargets: %s", p.CommandPattern, inTargets)
			params, paramPortsOpen := p.receiveParams()
			Debug.Printf("[%s] Got params: %s", p.CommandPattern, params)
			if !inPortsOpen && !paramPortsOpen {
				Debug.Printf("[%s] Breaking: Both inPorts and paramPorts closed", p.CommandPattern)
				break
			}
			if len(p.InPorts) == 0 && !paramPortsOpen {
				Debug.Printf("[%s] Breaking: No inports, and params closed", p.CommandPattern)
				break
			}
			if len(p.ParamPorts) == 0 && !inPortsOpen {
				Debug.Printf("[%s] Breaking: No params, and inPorts closed", p.CommandPattern)
				break
			}
			t := NewShellTask(p.CommandPattern, inTargets, p.OutPathFuncs, params, p.Prepend)
			ch <- t
			if len(p.InPorts) == 0 && len(p.ParamPorts) == 0 {
				Debug.Printf("[%s] Breaking: No inports nor params", p.CommandPattern)
				break
			}
		}
	}()
	return ch
}

func (p *ShellProcess) receiveInputs() (inTargets map[string]*FileTarget, inPortsOpen bool) {
	inPortsOpen = true
	inTargets = make(map[string]*FileTarget)
	// Read input targets on in-ports and set up path mappings
	for iname, ichan := range p.InPorts {
		Debug.Printf("[%s] Receieving on inPort %s ...", p.CommandPattern, iname)
		inTarget, open := <-ichan
		if !open {
			inPortsOpen = false
			continue
		}
		Debug.Printf("[%s] Got inTarget %s ...", p.CommandPattern, inTarget.GetPath())
		inTargets[iname] = inTarget
	}
	return
}

func (p *ShellProcess) receiveParams() (params map[string]string, paramPortsOpen bool) {
	paramPortsOpen = true
	params = make(map[string]string)
	// Read input targets on in-ports and set up path mappings
	for pname, pchan := range p.ParamPorts {
		pval, open := <-pchan
		if !open {
			paramPortsOpen = false
			continue
		}
		Debug.Println("Receiving param:", pname, "with value", pval)
		params[pname] = pval
	}
	return
}

func (p *ShellProcess) closeOutPorts() {
	for oname, oport := range p.OutPorts {
		Debug.Printf("[%s] Closing port %s ...\n", p.CommandPattern, oname)
		close(oport)
	}
}

func getPlaceHolderRegex() *re.Regexp {
	r, err := re.Compile("{(o|os|i|is|p):([^{}:]+)}")
	Check(err)
	return r
}

// ------- ShellTask -------

type ShellTask struct {
	InTargets  map[string]*FileTarget
	OutTargets map[string]*FileTarget
	Params     map[string]string
	Command    string
	Done       chan int
}

func NewShellTask(cmdPat string, inTargets map[string]*FileTarget, outPathFuncs map[string]func(*ShellTask) string, params map[string]string, prepend string) *ShellTask {
	t := &ShellTask{
		InTargets:  inTargets,
		OutTargets: make(map[string]*FileTarget),
		Params:     params,
		Command:    "",
		Done:       make(chan int),
	}
	// Create out targets
	Debug.Printf("[%s] Creating outTargets now ...", cmdPat)
	outTargets := make(map[string]*FileTarget)
	for oname, ofun := range outPathFuncs {
		opath := ofun(t)
		Debug.Printf("[%s] Creating outTarget with path %s ...", cmdPat, opath)
		outTargets[oname] = NewFileTarget(opath)
	}
	t.OutTargets = outTargets
	t.Command = formatCommand(cmdPat, inTargets, outTargets, params, prepend)
	Debug.Printf("[%s] Created formatted command: %s", cmdPat, t.Command)
	return t
}

func (t *ShellTask) Run() {
	defer close(t.Done) // TODO: Is this needed?
	if !t.anyOutputExists() {
		t.executeCommand(t.Command)
		t.atomizeTargets()
	}
	Debug.Printf("[%s] Starting to send Done in t.Run() ...)\n", t.Command)
	t.Done <- 1
	Debug.Printf("[%s] Done sending Done, in t.Run()\n", t.Command)
}

func (t *ShellTask) executeCommand(cmd string) {
	Info.Printf("[%s] Executing command: %s \n", t.Command, cmd)
	_, err := exec.Command("bash", "-c", cmd).Output()
	Check(err)
}

func (t *ShellTask) GetInPath(inPort string) string {
	return t.InTargets[inPort].GetPath()
}

func formatCommand(cmd string, inTargets map[string]*FileTarget, outTargets map[string]*FileTarget, params map[string]string, prepend string) string {

	// Debug.Println("Formatting command with the following data:")
	// Debug.Println("prepend:", prepend)
	// Debug.Println("cmd:", cmd)
	// Debug.Println("inTargets:", inTargets)
	// Debug.Println("outTargets:", outTargets)
	// Debug.Println("params:", params)

	r := getPlaceHolderRegex()
	ms := r.FindAllStringSubmatch(cmd, -1)
	for _, m := range ms {
		whole := m[0]
		typ := m[1]
		name := m[2]
		var newstr string
		if typ == "o" || typ == "os" {
			if outTargets[name] == nil {
				msg := fmt.Sprint("Missing outpath for outport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				if typ == "o" {
					newstr = outTargets[name].GetTempPath() // Means important to Atomize afterwards!
				} else if typ == "os" {
					newstr = outTargets[name].GetFifoPath()
				}
			}
		} else if typ == "i" {
			if inTargets[name] == nil {
				msg := fmt.Sprint("Missing intarget for inport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else if inTargets[name].GetPath() == "" {
				msg := fmt.Sprint("Missing inpath for inport '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				if typ == "i" {
					if inTargets[name].doStream {
						newstr = inTargets[name].GetFifoPath()
					} else {
						newstr = inTargets[name].GetPath()
					}
				}
			}
		} else if typ == "p" {
			if params[name] == "" {
				msg := fmt.Sprint("Missing param value param '", name, "' for command '", cmd, "'")
				Check(errors.New(msg))
			} else {
				newstr = params[name]
			}
		}
		if newstr == "" {
			msg := fmt.Sprint("Replace failed for port ", name, " forcommand '", cmd, "'")
			Check(errors.New(msg))
		}
		cmd = str.Replace(cmd, whole, newstr, -1)
	}
	// Add prepend string to the command
	if prepend != "" {
		cmd = fmt.Sprintf("%s %s", prepend, cmd)
	}
	return cmd
}

func (t *ShellTask) atomizeTargets() {
	for _, tgt := range t.OutTargets {
		if !tgt.doStream {
			Debug.Printf("Atomizing file: %s -> %s", tgt.GetTempPath(), tgt.GetPath())
			tgt.Atomize()
			Debug.Printf("Done atomizing file: %s -> %s", tgt.GetTempPath(), tgt.GetPath())
		} else {
			Debug.Printf("Target is streaming, so not atomizing: %s", tgt.GetPath())
		}
	}
}

func (t *ShellTask) anyOutputExists() (anyFileExists bool) {
	anyFileExists = false
	for _, tgt := range t.OutTargets {
		opath := tgt.GetPath()
		otmpPath := tgt.GetTempPath()
		ofifoPath := tgt.GetFifoPath()
		if _, err := os.Stat(opath); err == nil {
			Warn.Printf("[%s] Output file already exists: %s. Check your workflow for correctness!\n", t.Command, opath)
			anyFileExists = true
		}
		if _, err := os.Stat(otmpPath); err == nil {
			Warn.Printf("[%s] Temporary Output file already exists: %s. Check your workflow for correctness!\n", t.Command, otmpPath)
			anyFileExists = true
		}
		if _, err := os.Stat(ofifoPath); err == nil {
			Warn.Printf("[%s] FIFO Output file already exists: %s. Check your workflow for correctness!\n", t.Command, ofifoPath)
			anyFileExists = true
		}
	}
	return
}
<|endoftext|>


<commit_before>package design

import (
	. "github.com/goadesign/goa/design/apidsl"
)

// 管理者
var AdminAuth = APIKeySecurity("adminAuth", func() {
	Description("トークン(admin)")
	Header("X-Authorization")
})

// ユーザー
var GeneralAuth = APIKeySecurity("generalAuth", func() {
	Description("トークン(student)")
	Header("X-Authorization")
})
<commit_msg>add: cron header security<commit_after>package design

import (
	. "github.com/goadesign/goa/design/apidsl"
)

// 管理者
var AdminAuth = APIKeySecurity("adminAuth", func() {
	Description("トークン(admin)")
	Header("X-Authorization")
})

// ユーザー
var GeneralAuth = APIKeySecurity("generalAuth", func() {
	Description("トークン(student)")
	Header("X-Authorization")
})

// cron
var GAECronAuth = APIKeySecurity("cronAuth", func() {
	Description("gae cron")
	Header("X-Appengine-Cron")
})
<|endoftext|>


<commit_before>package main

import (
	"crypto/hmac"
	"crypto/md4"
	"crypto/md5"
	"crypto/ripemd160"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	"hash"
	"hash/adler32"
	"hash/crc32"
	"hash/crc64"
	"hash/fnv"
	"io"
	"os"
	"sort"
	"strings"
)

const (
	version   = "1.0"
	chunkSize = 32768 // Read files in 32KB chunks
)

var (
	alg  *string = flag.String("a", "sha256", "algorithm")
	key  *string = flag.String("k", "", "key (for hashes that use a key, e.g. HMAC)")
	salt *string = flag.String("salt", "", "salt")
	hashStr  *bool = flag.Bool("s", false, "hash a string")
)

var (
	algDescs = map[string]string{
		"adler32":         "Adler-32 checksum (RFC 1950)",
		"crc32":           "32-bit cyclic redundancy check (CRC-32) checksum (defaults to IEEE polynomial)",
		"crc32ieee":       "CRC-32 using the IEEE polynomial (0xedb88320)",
		"crc32castagnoli": "CRC-32 using the Castagnoli polynomial (0x82f63b78)",
		"crc32koopman":    "CRC-32 using the Koopman polynomial (0xeb31d82e)",
		"crc64":           "64-bit cyclic redundancy check (CRC-64) checksum (defaults to ISO polynomial)",
		"crc64iso":        "CRC-64 using the ISO polynomial (0xD800000000000000)",
		"crc64ecma":       "CRC-64 using the ECMA polynomial (0xC96C5795D7870F42)",
		"fnv":             "FNV-1 non-cryptographic hash (defaults to fnv32)",
		"fnv32":           "32-bit FNV-1",
		"fnv32a":          "32-bit FNV-1a",
		"fnv64":           "64-bit FNV-1",
		"fnv64a":          "64-bit FNV-1a",
		"hmac":            "Keyed-Hash Message Authentication Code (HMAC) (requires -k <key>) (defaults to SHA-256)",
		"hmacmd5":         "HMAC using MD5 (requires -k <key>)",
		"hmacsha1":        "HMAC using SHA-1 (requires -k <key>)",
		"hmacsha256":      "HMAC using SHA-256 (requires -k <key>)",
		"hmacsha512":      "HMAC using SHA-512 (requires -k <key>)",
		"md4":             "MD4 hash (RFC 1320)",
		"md5":             "MD5 hash (RFC 1321)",
		"ripemd160":       "RIPEMD-160 hash",
		"sha1":            "SHA-1 hash (RFC 3174)",
		"sha224":          "SHA-224 hash (FIPS 180-2)",
		"sha256":          "SHA-256 hash (FIPS 180-2)",
		"sha384":          "SHA-384 hash (FIPS 180-2)",
		"sha512":          "SHA-512 hash (FIPS 180-2)",
	}
)

func GetGenerator(a string) (hash.Hash, os.Error) {
	var g hash.Hash
	switch a {
	default:
		return md5.New(), os.NewError("Invalid algorithm")
	case "adler32":
		g = adler32.New()
	case "crc32", "crc32ieee":
		g = crc32.New(crc32.MakeTable(crc32.IEEE))
	case "crc32castagnoli":
		g = crc32.New(crc32.MakeTable(crc32.Castagnoli))
	case "crc32koopman":
		g = crc32.New(crc32.MakeTable(crc32.Koopman))
	case "crc64", "crc64iso":
		g = crc64.New(crc64.MakeTable(crc64.ISO))
	case "crc64ecma":
		g = crc64.New(crc64.MakeTable(crc64.ECMA))
	case "fnv", "fnv32":
		g = fnv.New32()
	case "fnv32a":
		g = fnv.New32a()
	case "fnv64":
		g = fnv.New64()
	case "fnv64a":
		g = fnv.New64a()
	case "hmac", "hmacsha256":
		g = hmac.NewSHA256([]byte(*key))
	case "hmacmd5":
		g = hmac.NewMD5([]byte(*key))
	case "hmacsha1":
		g = hmac.NewSHA1([]byte(*key))
	case "hmacsha512":
		g = hmac.New(sha512.New, []byte(*key))
	case "md4":
		g = md4.New()
	case "md5":
		g = md5.New()
	case "ripemd160":
		g = ripemd160.New()
	case "sha1":
		g = sha1.New()
	case "sha224":
		g = sha256.New224()
	case "sha256":
		g = sha256.New()
	case "sha384":
		g = sha512.New384()
	case "sha512":
		g = sha512.New()
	}
	return g, nil
}

func HashString(gen hash.Hash, s string) string {
	gen.Write([]byte(s))
	return fmt.Sprintf("%x", gen.Sum())
}

func HashFile(gen hash.Hash, f io.Reader) (string, os.Error) {
	buf := make([]byte, chunkSize)
	gen.Write([]byte(*salt))
	for {
		bytesRead, err := f.Read(buf)
		if err != nil {
			if err == os.EOF && bytesRead == 0 { // Empty file
				gen.Write([]byte(""))
			} else {
				return "", err
			}
		} else {
			gen.Write(buf[:bytesRead])
		}
		if bytesRead < chunkSize { // EOF
			break
		}
	}
	return fmt.Sprintf("%x", gen.Sum()), nil
}

func Usage() {
	fmt.Println("Usage:", os.Args[0], "[-a <algorithm>] [-salt <salt>] [-s <string to hash>] / <file(s) to hash>\n")
	fmt.Println("Examples:")
	fmt.Println(" ", os.Args[0], `-a md5 document.txt               `, "Generate MD5 digest of a file")
	fmt.Println(" ", os.Args[0], `-a md5 *                          `, "Generate MD5 digests of all files in folder")
	fmt.Println(" ", os.Args[0], `-a sha1 -s hello world            `, "Generate SHA-1 digest of a string")
	fmt.Println(" ", os.Args[0], `-a sha1 -salt s4lt -s hello world `, "Generate salted SHA-1 digest of a string")
	fmt.Println(" ", os.Args[0], `-a hmacsha1 -k k3y -s untouched   `, "Generate HMAC of a string using SHA-1")
	fmt.Println("")
	fmt.Println("Available algorithms (default is SHA-256):")
	mk := make([]string, len(algDescs))
	i := 0
	for k, _ := range algDescs {
		mk[i] = k
		i++
	}
	sort.Strings(mk)
	for _, v := range mk {
		fmt.Printf("  %-15s %s\n", v, algDescs[v])
	}
	fmt.Println("")
	fmt.Println(`Note: For complex strings, put the string in a file, then run Picugen on
      the file. (Don't add newlines to the file as they will alter the output.)`)
}

func main() {
	flag.Parse()
	if flag.NArg() == 0 {
		Usage()
		return
	}
	*alg = strings.ToLower(*alg)
	gen, err := GetGenerator(*alg)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	if *hashStr {
		var s string
		for i, word := range flag.Args() {
			if i > 0 {
				s += " "
			}
			s += word
		}
		fmt.Println(HashString(gen, *salt+s))
	} else {
		for _, path := range flag.Args() {
			var res string
			f, err := os.Open(path)
			if err != nil {
				res = err.String()
			} else {
				h, err := HashFile(gen, f)
				if err != nil {
					res = err.String()
				} else {
					res = h
				}
			}
			fmt.Println(res, "", path)
			f.Close()
			gen.Reset()
		}
	}
}
<commit_msg>TIL about io.Copy<commit_after>package main

import (
	"crypto/hmac"
	"crypto/md4"
	"crypto/md5"
	"crypto/ripemd160"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	"hash"
	"hash/adler32"
	"hash/crc32"
	"hash/crc64"
	"hash/fnv"
	"io"
	"os"
	"sort"
	"strings"
)

const (
	version   = "1.0"
)

var (
	alg  *string = flag.String("a", "sha256", "algorithm")
	key  *string = flag.String("k", "", "key (for hashes that use a key, e.g. HMAC)")
	salt *string = flag.String("salt", "", "salt")
	hashStr  *bool = flag.Bool("s", false, "hash a string")
)

var (
	algDescs = map[string]string{
		"adler32":         "Adler-32 checksum (RFC 1950)",
		"crc32":           "32-bit cyclic redundancy check (CRC-32) checksum (defaults to IEEE polynomial)",
		"crc32ieee":       "CRC-32 using the IEEE polynomial (0xedb88320)",
		"crc32castagnoli": "CRC-32 using the Castagnoli polynomial (0x82f63b78)",
		"crc32koopman":    "CRC-32 using the Koopman polynomial (0xeb31d82e)",
		"crc64":           "64-bit cyclic redundancy check (CRC-64) checksum (defaults to ISO polynomial)",
		"crc64iso":        "CRC-64 using the ISO polynomial (0xD800000000000000)",
		"crc64ecma":       "CRC-64 using the ECMA polynomial (0xC96C5795D7870F42)",
		"fnv":             "FNV-1 non-cryptographic hash (defaults to fnv32)",
		"fnv32":           "32-bit FNV-1",
		"fnv32a":          "32-bit FNV-1a",
		"fnv64":           "64-bit FNV-1",
		"fnv64a":          "64-bit FNV-1a",
		"hmac":            "Keyed-Hash Message Authentication Code (HMAC) (requires -k <key>) (defaults to SHA-256)",
		"hmacmd5":         "HMAC using MD5 (requires -k <key>)",
		"hmacsha1":        "HMAC using SHA-1 (requires -k <key>)",
		"hmacsha256":      "HMAC using SHA-256 (requires -k <key>)",
		"hmacsha512":      "HMAC using SHA-512 (requires -k <key>)",
		"md4":             "MD4 hash (RFC 1320)",
		"md5":             "MD5 hash (RFC 1321)",
		"ripemd160":       "RIPEMD-160 hash",
		"sha1":            "SHA-1 hash (RFC 3174)",
		"sha224":          "SHA-224 hash (FIPS 180-2)",
		"sha256":          "SHA-256 hash (FIPS 180-2)",
		"sha384":          "SHA-384 hash (FIPS 180-2)",
		"sha512":          "SHA-512 hash (FIPS 180-2)",
	}
)

func GetGenerator(a string) (hash.Hash, os.Error) {
	var g hash.Hash
	switch a {
	default:
		return md5.New(), os.NewError("Invalid algorithm")
	case "adler32":
		g = adler32.New()
	case "crc32", "crc32ieee":
		g = crc32.New(crc32.MakeTable(crc32.IEEE))
	case "crc32castagnoli":
		g = crc32.New(crc32.MakeTable(crc32.Castagnoli))
	case "crc32koopman":
		g = crc32.New(crc32.MakeTable(crc32.Koopman))
	case "crc64", "crc64iso":
		g = crc64.New(crc64.MakeTable(crc64.ISO))
	case "crc64ecma":
		g = crc64.New(crc64.MakeTable(crc64.ECMA))
	case "fnv", "fnv32":
		g = fnv.New32()
	case "fnv32a":
		g = fnv.New32a()
	case "fnv64":
		g = fnv.New64()
	case "fnv64a":
		g = fnv.New64a()
	case "hmac", "hmacsha256":
		g = hmac.NewSHA256([]byte(*key))
	case "hmacmd5":
		g = hmac.NewMD5([]byte(*key))
	case "hmacsha1":
		g = hmac.NewSHA1([]byte(*key))
	case "hmacsha512":
		g = hmac.New(sha512.New, []byte(*key))
	case "md4":
		g = md4.New()
	case "md5":
		g = md5.New()
	case "ripemd160":
		g = ripemd160.New()
	case "sha1":
		g = sha1.New()
	case "sha224":
		g = sha256.New224()
	case "sha256":
		g = sha256.New()
	case "sha384":
		g = sha512.New384()
	case "sha512":
		g = sha512.New()
	}
	return g, nil
}

func HashString(gen hash.Hash, s string) string {
	gen.Write([]byte(s))
	return fmt.Sprintf("%x", gen.Sum())
}

func HashFile(gen hash.Hash, f io.Reader) (string, os.Error) {
	gen.Write([]byte(*salt))
	_, err := io.Copy(gen, f)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%x", gen.Sum()), nil
}

func Usage() {
	fmt.Println("Usage:", os.Args[0], "[-a <algorithm>] [-salt <salt>] [-s <string to hash>] / <file(s) to hash>\n")
	fmt.Println("Examples:")
	fmt.Println(" ", os.Args[0], `-a md5 document.txt               `, "Generate MD5 digest of a file")
	fmt.Println(" ", os.Args[0], `-a md5 *                          `, "Generate MD5 digests of all files in folder")
	fmt.Println(" ", os.Args[0], `-a sha1 -s hello world            `, "Generate SHA-1 digest of a string")
	fmt.Println(" ", os.Args[0], `-a sha1 -salt s4lt -s hello world `, "Generate salted SHA-1 digest of a string")
	fmt.Println(" ", os.Args[0], `-a hmacsha1 -k k3y -s untouched   `, "Generate HMAC of a string using SHA-1")
	fmt.Println("")
	fmt.Println("Available algorithms (default is SHA-256):")
	mk := make([]string, len(algDescs))
	i := 0
	for k, _ := range algDescs {
		mk[i] = k
		i++
	}
	sort.Strings(mk)
	for _, v := range mk {
		fmt.Printf("  %-15s %s\n", v, algDescs[v])
	}
	fmt.Println("")
	fmt.Println(`Note: For complex strings, put the string in a file, then run Picugen on
      the file. (Don't add newlines to the file as they will alter the output.)`)
}

func main() {
	flag.Parse()
	if flag.NArg() == 0 {
		Usage()
		return
	}
	*alg = strings.ToLower(*alg)
	gen, err := GetGenerator(*alg)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	if *hashStr {
		var s string
		for i, word := range flag.Args() {
			if i > 0 {
				s += " "
			}
			s += word
		}
		fmt.Println(HashString(gen, *salt+s))
	} else {
		for _, path := range flag.Args() {
			var res string
			f, err := os.Open(path)
			if err != nil {
				res = err.String()
			} else {
				h, err := HashFile(gen, f)
				if err != nil {
					res = err.String()
				} else {
					res = h
				}
			}
			fmt.Println(res, "", path)
			f.Close()
			gen.Reset()
		}
	}
}
<|endoftext|>


<commit_before>package models

import (
    "time"
)

const (
    CANDIDATE uint = 0
    TRAIN     uint = 1
    VAL       uint = 2
)

type File struct {
    Id        int       `xorm:"pk autoincr"                 json:"file_id,omitempty"`
    Key       string    `xorm:"varchar(128) notnull unique" json:"key,omitempty"`
    Width     int       `xorm:"integer(4)"                  josn:"width,omitempty"`
    Height    int       `xorm:"integer(4)"                  json:"height,omitempty"`
    CreatedAt time.Time `xorm:"created"                     json:"created_at,omitempty"`
}

type Tag struct {
    Id        int       `xorm:"pk autoincr"                 json:"tag_id,omitempty"`
    Name      string    `xorm:"varchar(128) notnull unique" json:"name,omitempty"`
    CreatedAt time.Time `xorm:"created"                     json:"created_at,omitempty"`
}

type Dataset struct {
    Id        int       `xorm:"pk autoincr"           json:"dataset_id,omitempty"`
    TagId     int       `xorm:"unique(tag_file)"      json:"tag_id,omitempty"`
    Tag       *Tag      `xorm:"-"                     json:"tag,omitempty"`
    FileId    int       `xorm:"unique(tag_file)"      json:"file_id,omitempty"`
    File      *File     `xorm:"-"                     json:"file,omitempty"`
    DataType  uint      `xorm:"tinyint(1) default(0)" json:"data_type,omitempty"`
    CreatedAt time.Time `xorm:"created"               json:"created_at,omitempty"`
}

func (dataset *Dataset) FillObject() (err error) {
    var tag = &Tag{Id: dataset.TagId}
    var has bool

    if has, err = engine.Get(tag); err != nil {
        return
    } else if has {
        dataset.Tag = tag
    }

    var file = &File{Id: dataset.FileId}
    if has, err = engine.Get(file); err != nil {
        return
    } else if has {
        dataset.File = file
    }

    return
}

func (dataset *Dataset) SetFile(file *File) {
    dataset.File = file
    dataset.FileId = file.Id
}

func (dataset *Dataset) SetTag(tag *Tag) {
    dataset.Tag = tag
    dataset.TagId = tag.Id
}
<commit_msg>Fix. typos<commit_after>package models

import (
    "time"
)

const (
    CANDIDATE uint = 0
    TRAIN     uint = 1
    VAL       uint = 2
)

type File struct {
    Id        int       `xorm:"pk autoincr"                 json:"file_id,omitempty"`
    Key       string    `xorm:"varchar(128) notnull unique" json:"key,omitempty"`
    Width     int       `xorm:"integer(4)"                  json:"width,omitempty"`
    Height    int       `xorm:"integer(4)"                  json:"height,omitempty"`
    CreatedAt time.Time `xorm:"created"                     json:"created_at,omitempty"`
}

type Tag struct {
    Id        int       `xorm:"pk autoincr"                 json:"tag_id,omitempty"`
    Name      string    `xorm:"varchar(128) notnull unique" json:"name,omitempty"`
    CreatedAt time.Time `xorm:"created"                     json:"created_at,omitempty"`
}

type Dataset struct {
    Id        int       `xorm:"pk autoincr"           json:"dataset_id,omitempty"`
    TagId     int       `xorm:"unique(tag_file)"      json:"tag_id,omitempty"`
    Tag       *Tag      `xorm:"-"                     json:"tag,omitempty"`
    FileId    int       `xorm:"unique(tag_file)"      json:"file_id,omitempty"`
    File      *File     `xorm:"-"                     json:"file,omitempty"`
    DataType  uint      `xorm:"tinyint(1) default(0)" json:"data_type,omitempty"`
    CreatedAt time.Time `xorm:"created"               json:"created_at,omitempty"`
}

func (dataset *Dataset) FillObject() (err error) {
    var tag = &Tag{Id: dataset.TagId}
    var has bool

    if has, err = engine.Get(tag); err != nil {
        return
    } else if has {
        dataset.Tag = tag
    }

    var file = &File{Id: dataset.FileId}
    if has, err = engine.Get(file); err != nil {
        return
    } else if has {
        dataset.File = file
    }

    return
}

func (dataset *Dataset) SetFile(file *File) {
    dataset.File = file
    dataset.FileId = file.Id
}

func (dataset *Dataset) SetTag(tag *Tag) {
    dataset.Tag = tag
    dataset.TagId = tag.Id
}
<|endoftext|>


<commit_before>package models

import (
	"strconv"
	"errors"

	"github.com/dmitry-kuchura/access-application/app"
)

const (
	insertDomain = `
	INSERT INTO domains (name, url, description, status, created_at, updated_at)
	VALUES(?, ?, ?, 1, NOW(), NOW()) ON DUPLICATE KEY UPDATE
	name = VALUES(name)
	`

	checkDomain = `
	SELECT COUNT(*) as count FROM domains WHERE name LIKE ? OR url LIKE ?
	`

	selectAllDomains = `
	SELECT id, name, url, status, updated_at
	FROM domains
	LIMIT ?
	OFFSET ?
	`
	countAllDomains = `
	SELECT COUNT(*) as count
	FROM domains
	`

	deleteDomain = `
	DELETE FROM domains WHERE id = ?
	`

	selectDomain = `
	SELECT id, name, url, status, updated_at FROM domains WHERE id = ?
	`
)

type Domain struct {
	ID          int        `form:"id" json:"id"`
	Name        string     `form:"name" json:"name"`
	Url         string     `form:"url" json:"url"`
	Description string     `form:"description" json:"description"`
	Status      int        `form:"status" json:"status"`
	Updated     string     `form:"updated_at" json:"updated_at"`
	Ftps        []Ftp      `form:"ftp" json:"ftp"`
	Databases   []Database `form:"database" json:"database"`
	Hostings    []Hosting  `form:"hosting" json:"hosting"`
	Admins      []Admin    `form:"admin" json:"admin"`
}

type DomainInterface interface {
	Domain(id int) (*Domain, error)
	CreateDomain(name, url, description string) (string, error)
	AllDomains(param string) (domains []Domain, count int, err error)
	DeleteDomain(id int) (bool, error)
	GetDomain(param int) (domains []Domain, err error)
}

// Добавление домена
func CreateDomain(name, url, description string) (string, error) {
	if CheckDomain(name, url) {
		res, err := app.Exec(insertDomain, name, url, description)

		id, err := res.LastInsertId()
		if err != nil {
			return "", err
		}
		return strconv.FormatInt(id, 10), nil
	} else {
		err := errors.New("Domain was already created!")
		return "", err
	}
}

// Список доменов
func AllDomains(param string) (domains []Domain, count int, err error) {
	limit := 15
	page, _ := strconv.Atoi(param)
	offset := (page - 1) * limit

	rows, err := app.Query(selectAllDomains, limit, offset)

	row, _ := app.Query(countAllDomains)

	allDomain := app.CountRows(row)

	pages := allDomain / limit

	if err != nil {
		return domains, pages, err
	}

	defer rows.Close()
	for rows.Next() {
		d := Domain{}
		err = rows.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, pages, err
		}
		domains = append(domains, d)
	}
	err = rows.Err()
	return domains, pages, err
}

// Удаление домена
func DeleteDomain(id int) (bool, error) {
	_, err := app.Exec(deleteDomain, id)

	if err == nil {
		return true, nil
	} else {
		return false, err
	}
}

// Получение конкретного домена
func GetDomain(param int) (domains []Domain, err error) {
	row, err := app.Query(selectDomain, param)
	defer row.Close()

	ftp, err := SelectFtps(param)
	mysql, err := SelectDatabases(param)
	admin, err := SelectAdmins(param)
	hosting, err := SelectHosting(param)

	for row.Next() {
		d := Domain{}
		err = row.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, err
		}

		d.Ftps = ftp
		d.Databases = mysql
		d.Admins = admin
		d.Hostings = hosting

		domains = append(domains, d)
	}
	err = row.Err()

	return domains, err
}

func CheckDomain(name, url string) bool {
	res, _ := app.Query(checkDomain, name, url)

	if app.CountRows(res) >= 1 {
		return false
	} else {
		return true
	}
}
<commit_msg>Update domains.go<commit_after>package models

import (
	"strconv"
	"errors"

	"github.com/dmitry-kuchura/access-application/app"
)

const (
	insertDomain = `
	INSERT INTO domains (name, url, description, status, created_at, updated_at)
	VALUES(?, ?, ?, 1, NOW(), NOW()) ON DUPLICATE KEY UPDATE
	name = VALUES(name)
	`

	checkDomain = `
	SELECT COUNT(*) as count FROM domains WHERE name LIKE ? OR url LIKE ?
	`

	selectAllDomains = `
	SELECT id, name, url, status, updated_at
	FROM domains
	LIMIT ?
	OFFSET ?
	`
	countAllDomains = `
	SELECT COUNT(*) as count
	FROM domains
	`

	deleteDomain = `
	DELETE FROM domains WHERE id = ?
	`

	selectDomain = `
	SELECT id, name, url, status, updated_at FROM domains WHERE id = ?
	`
)

type Domain struct {
	ID          int        `form:"id" json:"id"`
	Name        string     `form:"name" json:"name"`
	Url         string     `form:"url" json:"url"`
	Description string     `form:"description" json:"description"`
	Status      int        `form:"status" json:"status"`
	Updated     string     `form:"updated_at" json:"updated_at"`
	Ftps        []Ftp      `form:"ftp" json:"ftp"`
	Databases   []Database `form:"database" json:"database"`
	Hosting     []Hosting  `form:"hosting" json:"hosting"`
	Admins      []Admin    `form:"admin" json:"admin"`
}

// Добавление домена
func CreateDomain(name, url, description string) (string, error) {
	if CheckDomain(name, url) {
		res, err := app.Exec(insertDomain, name, url, description)

		id, err := res.LastInsertId()
		if err != nil {
			return "", err
		}
		return strconv.FormatInt(id, 10), nil
	} else {
		err := errors.New("Domain was already created!")
		return "", err
	}
}

// Список доменов
func AllDomains(param string) (domains []Domain, count int, err error) {
	limit := 15
	page, _ := strconv.Atoi(param)
	offset := (page - 1) * limit

	rows, err := app.Query(selectAllDomains, limit, offset)

	row, _ := app.Query(countAllDomains)

	allDomain := app.CountRows(row)

	pages := allDomain / limit

	if err != nil {
		return domains, pages, err
	}

	defer rows.Close()
	for rows.Next() {
		d := Domain{}
		err = rows.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, pages, err
		}
		domains = append(domains, d)
	}
	err = rows.Err()
	return domains, pages, err
}

// Удаление домена
func DeleteDomain(id int) (bool, error) {
	_, err := app.Exec(deleteDomain, id)

	if err == nil {
		return true, nil
	} else {
		return false, err
	}
}

// Получение конкретного домена
func GetDomain(param int) (domains []Domain, err error) {
	row, err := app.Query(selectDomain, param)
	defer row.Close()

	ftp, err := SelectFtps(param)
	mysql, err := SelectDatabases(param)
	admin, err := SelectAdmins(param)
	hosting, err := SelectHosting(param)

	for row.Next() {
		d := Domain{}
		err = row.Scan(&d.ID, &d.Name, &d.Url, &d.Status, &d.Updated)
		if err != nil {
			return domains, err
		}

		d.Ftps = ftp
		d.Databases = mysql
		d.Admins = admin
		d.Hosting = hosting

		domains = append(domains, d)
	}
	err = row.Err()

	return domains, err
}

// Проверка на уникальность существовавния вводимого домена
func CheckDomain(name, url string) bool {
	res, _ := app.Query(checkDomain, name, url)

	if app.CountRows(res) >= 1 {
		return false
	} else {
		return true
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Unknwon
//
// 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 models

import (
	"bytes"
	"errors"
	"fmt"
	"path"
	"strings"
	"time"

	"github.com/Unknwon/com"

	"github.com/Unknwon/gowalker/modules/base"
	"github.com/Unknwon/gowalker/modules/setting"
)

var (
	ErrEmptyPackagePath     = errors.New("Package import path is empty")
	ErrPackageNotFound      = errors.New("Package does not found")
	ErrPackageVersionTooOld = errors.New("Package version is too old")
)

// PkgInfo represents the package information.
type PkgInfo struct {
	ID         int64  `xorm:"pk autoincr"`
	Name       string `xorm:"-"`
	ImportPath string `xorm:"UNIQUE"`
	Etag       string

	ProjectPath string
	ViewDirPath string
	Synopsis    string

	IsCmd       bool
	IsCgo       bool
	IsGoRepo    bool
	IsGoSubrepo bool
	IsGaeRepo   bool

	PkgVer int

	Priority int `xorm:" NOT NULL"`
	Views    int64
	Stars    int64
	// Indicate how many JS should be downloaded(JsNum=total num - 1)
	JsNum int

	ImportNum int64
	ImportIDs string `xorm:"import_ids LONGTEXT"`
	// Import num usually is small so save it to reduce a database query.
	ImportPaths string `xorm:"LONGTEXT"`

	RefNum int64
	RefIDs string `xorm:"ref_ids LONGTEXT"`

	Subdirs string `xorm:"TEXT"`

	LastViewed int64 `xorm:"-"`
	Created    int64
}

func (p *PkgInfo) JSPath() string {
	return path.Join(setting.DocsJsPath, p.ImportPath) + ".js"
}

// CanRefresh returns true if package is available to refresh.
func (p *PkgInfo) CanRefresh() bool {
	return time.Now().UTC().Add(-1*setting.RefreshInterval).Unix() > p.Created
}

// GetRefs returns a list of packages that import this one.
func (p *PkgInfo) GetRefs() []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, p.RefNum)
	refIDs := strings.Split(p.RefIDs, "|")
	for i := range refIDs {
		if len(refIDs[i]) == 0 {
			continue
		}

		id := com.StrTo(refIDs[i][1:]).MustInt64()
		if pinfo, _ := GetPkgInfoById(id); pinfo != nil {
			pinfo.Name = path.Base(pinfo.ImportPath)
			pinfos = append(pinfos, pinfo)
		}
	}
	return pinfos
}

// PACKAGE_VER is modified when previously stored packages are invalid.
const PACKAGE_VER = 1

// PkgRef represents temporary reference information of a package.
type PkgRef struct {
	ID         int64  `xorm:"pk autoincr"`
	ImportPath string `xorm:"UNIQUE"`
	RefNum     int64
	RefIDs     string `xorm:"ref_ids LONGTEXT"`
}

func updatePkgRef(pid int64, refPath string) error {
	if base.IsGoRepoPath(refPath) ||
		refPath == "C" ||
		refPath[1] == '.' ||
		!base.IsValidRemotePath(refPath) {
		return nil
	}

	ref := new(PkgRef)
	has, err := x.Where("import_path=?", refPath).Get(ref)
	if err != nil {
		return fmt.Errorf("get PkgRef: %v", err)
	}

	queryStr := "$" + com.ToStr(pid) + "|"
	if !has {
		if _, err = x.Insert(&PkgRef{
			ImportPath: refPath,
			RefNum:     1,
			RefIDs:     queryStr,
		}); err != nil {
			return fmt.Errorf("insert PkgRef: %v", err)
		}
		return nil
	}

	i := strings.Index(ref.RefIDs, queryStr)
	if i > -1 {
		return nil
	}

	ref.RefIDs += queryStr
	ref.RefNum++
	_, err = x.Id(ref.ID).AllCols().Update(ref)
	return err
}

// checkRefs checks if given packages are still referencing this one.
func checkRefs(pinfo *PkgInfo) {
	var buf bytes.Buffer
	pinfo.RefNum = 0
	refIDs := strings.Split(pinfo.RefIDs, "|")
	for i := range refIDs {
		if len(refIDs[i]) == 0 {
			continue
		}

		fmt.Println(com.StrTo(refIDs[i][1:]).MustInt64())
		pkg, _ := GetPkgInfoById(com.StrTo(refIDs[i][1:]).MustInt64())
		if pkg == nil {
			continue
		}

		if strings.Index(pkg.ImportIDs, "$"+com.ToStr(pinfo.ID)+"|") == -1 {
			continue
		}

		buf.WriteString("$")
		buf.WriteString(com.ToStr(pkg.ID))
		buf.WriteString("|")
		pinfo.RefNum++
	}
	pinfo.RefIDs = buf.String()
}

// updateRef updates or crates corresponding reference import information.
func updateRef(pid int64, refPath string) (int64, error) {
	if len(refPath) == 0 {
		return 0, nil
	}

	pinfo, err := GetPkgInfo(refPath)
	if err != nil && pinfo == nil {
		if err == ErrPackageNotFound ||
			err == ErrPackageVersionTooOld {
			// Package hasn't existed yet, save to temporary place.
			return 0, updatePkgRef(pid, refPath)
		}
		return 0, fmt.Errorf("GetPkgInfo(%s): %v", refPath, err)
	}

	// Check if reference information has beed recorded.
	queryStr := "$" + com.ToStr(pid) + "|"
	i := strings.Index(pinfo.RefIDs, queryStr)
	if i > -1 {
		return pinfo.ID, nil
	}

	// Add new as needed.
	pinfo.RefIDs += queryStr
	pinfo.RefNum++
	_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
	return pinfo.ID, err
}

// SavePkgInfo saves package information.
func SavePkgInfo(pinfo *PkgInfo, updateRefs bool) (err error) {
	if len(pinfo.Synopsis) > 255 {
		pinfo.Synopsis = pinfo.Synopsis[:255]
	}

	pinfo.PkgVer = PACKAGE_VER

	switch {
	case pinfo.IsGaeRepo:
		pinfo.Priority = 70
	case pinfo.IsGoSubrepo:
		pinfo.Priority = 80
	case pinfo.IsGoRepo:
		pinfo.Priority = 99
	}

	// When package is not created, there is no ID so check will certainly fail.
	var ignoreCheckRefs bool

	// Create or update package info itself.
	// Note(Unknwon): do this because we need ID field later.
	if pinfo.ID == 0 {
		ignoreCheckRefs = true
		pinfo.Views = 1

		// First time created, check PkgRef.
		ref := new(PkgRef)
		has, err := x.Where("import_path=?", pinfo.ImportPath).Get(ref)
		if err != nil {
			return fmt.Errorf("get PkgRef: %v", err)
		} else if has {
			pinfo.RefNum = ref.RefNum
			pinfo.RefIDs = ref.RefIDs
			if _, err = x.Id(ref.ID).Delete(ref); err != nil {
				return fmt.Errorf("delete PkgRef: %v", err)
			}
		}

		_, err = x.Insert(pinfo)
	} else {
		_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
	}
	if err != nil {
		return fmt.Errorf("update package info: %v", err)
	}

	// Update package import references.
	// Note(Unknwon): I just don't see the value of who imports STD
	//	when you don't even import and uses what objects.
	if updateRefs && !pinfo.IsGoRepo {
		var buf bytes.Buffer
		paths := strings.Split(pinfo.ImportPaths, "|")
		for i := range paths {
			if base.IsGoRepoPath(paths[i]) {
				continue
			}

			refID, err := updateRef(pinfo.ID, paths[i])
			if err != nil {
				return fmt.Errorf("updateRef: %v", err)
			} else if refID == 0 {
				continue
			}
			buf.WriteString("$")
			buf.WriteString(com.ToStr(refID))
			buf.WriteString("|")
		}
		pinfo.ImportIDs = buf.String()

		if !ignoreCheckRefs {
			// Check packages who import this is still importing.
			checkRefs(pinfo)
		}
		_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
		return err
	}
	return nil
}

// GetPkgInfo returns package information by given import path.
func GetPkgInfo(importPath string) (*PkgInfo, error) {
	if len(importPath) == 0 {
		return nil, ErrEmptyPackagePath
	}

	pinfo := new(PkgInfo)
	has, err := x.Where("import_path=?", importPath).Get(pinfo)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, ErrPackageNotFound
	} else if pinfo.PkgVer < PACKAGE_VER {
		pinfo.Etag = ""
		return pinfo, ErrPackageVersionTooOld
	}

	if !com.IsFile(pinfo.JSPath()) {
		pinfo.Etag = ""
		return pinfo, ErrPackageVersionTooOld
	}

	return pinfo, nil
}

// GetSubPkgs returns sub-projects by given sub-directories.
func GetSubPkgs(importPath string, dirs []string) []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, len(dirs))
	for _, dir := range dirs {
		if len(dir) == 0 {
			continue
		}

		fullPath := importPath + "/" + dir
		if pinfo, err := GetPkgInfo(fullPath); err == nil {
			pinfo.Name = dir
			pinfos = append(pinfos, pinfo)
		} else {
			pinfos = append(pinfos, &PkgInfo{
				Name:       dir,
				ImportPath: fullPath,
			})
		}
	}
	return pinfos
}

// GetPkgInfosByPaths returns a list of packages by given import paths.
func GetPkgInfosByPaths(paths []string) []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, len(paths))
	for _, p := range paths {
		if len(p) == 0 {
			continue
		}

		if pinfo, err := GetPkgInfo(p); err == nil {
			pinfo.Name = path.Base(p)
			pinfos = append(pinfos, pinfo)
		} else {
			pinfos = append(pinfos, &PkgInfo{
				Name:       path.Base(p),
				ImportPath: p,
			})
		}
	}
	return pinfos
}

// GetPkgInfoById returns package information by given ID.
func GetPkgInfoById(id int64) (*PkgInfo, error) {
	pinfo := new(PkgInfo)
	has, err := x.Id(id).Get(pinfo)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, ErrPackageNotFound
	} else if pinfo.PkgVer < PACKAGE_VER {
		return pinfo, ErrPackageVersionTooOld
	}

	if !com.IsFile(pinfo.JSPath()) {
		return pinfo, ErrPackageVersionTooOld
	}

	return pinfo, nil
}

// GetPkgInfosByIDs returns a list of package info by given IDs.
func GetPkgInfosByIDs(ids []int64) ([]*PkgInfo, error) {
	pkgInfos := make([]*PkgInfo, 0, len(ids))
	return pkgInfos, x.Where("id > 0").In("id", base.Int64sToStrings(ids)).Find(&pkgInfos)
}

func getRepos(trueCondition string) ([]*PkgInfo, error) {
	pkgs := make([]*PkgInfo, 0, 100)
	return pkgs, x.Desc("views").Where(trueCondition+"=?", true).Find(&pkgs)
}

func GetGoRepos() ([]*PkgInfo, error) {
	return getRepos("is_go_repo")
}

func GetGoSubepos() ([]*PkgInfo, error) {
	return getRepos("is_go_subrepo")
}

func GetGAERepos() ([]*PkgInfo, error) {
	return getRepos("is_gae_repo")
}

// SearchPkgInfo searches package information by given keyword.
func SearchPkgInfo(limit int, keyword string) ([]*PkgInfo, error) {
	if len(keyword) == 0 {
		return nil, nil
	}
	pkgs := make([]*PkgInfo, 0, limit)
	return pkgs, x.Limit(limit).Desc("priority").Desc("stars").Desc("views").Where("import_path like ?", "%"+keyword+"%").Find(&pkgs)
}

func DeletePackageByPath(importPath string) error {
	_, err := x.Delete(&PkgInfo{ImportPath: importPath})
	return err
}
<commit_msg>Add 0 length check<commit_after>// Copyright 2015 Unknwon
//
// 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 models

import (
	"bytes"
	"errors"
	"fmt"
	"path"
	"strings"
	"time"

	"github.com/Unknwon/com"

	"github.com/Unknwon/gowalker/modules/base"
	"github.com/Unknwon/gowalker/modules/setting"
)

var (
	ErrEmptyPackagePath     = errors.New("Package import path is empty")
	ErrPackageNotFound      = errors.New("Package does not found")
	ErrPackageVersionTooOld = errors.New("Package version is too old")
)

// PkgInfo represents the package information.
type PkgInfo struct {
	ID         int64  `xorm:"pk autoincr"`
	Name       string `xorm:"-"`
	ImportPath string `xorm:"UNIQUE"`
	Etag       string

	ProjectPath string
	ViewDirPath string
	Synopsis    string

	IsCmd       bool
	IsCgo       bool
	IsGoRepo    bool
	IsGoSubrepo bool
	IsGaeRepo   bool

	PkgVer int

	Priority int `xorm:" NOT NULL"`
	Views    int64
	Stars    int64
	// Indicate how many JS should be downloaded(JsNum=total num - 1)
	JsNum int

	ImportNum int64
	ImportIDs string `xorm:"import_ids LONGTEXT"`
	// Import num usually is small so save it to reduce a database query.
	ImportPaths string `xorm:"LONGTEXT"`

	RefNum int64
	RefIDs string `xorm:"ref_ids LONGTEXT"`

	Subdirs string `xorm:"TEXT"`

	LastViewed int64 `xorm:"-"`
	Created    int64
}

func (p *PkgInfo) JSPath() string {
	return path.Join(setting.DocsJsPath, p.ImportPath) + ".js"
}

// CanRefresh returns true if package is available to refresh.
func (p *PkgInfo) CanRefresh() bool {
	return time.Now().UTC().Add(-1*setting.RefreshInterval).Unix() > p.Created
}

// GetRefs returns a list of packages that import this one.
func (p *PkgInfo) GetRefs() []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, p.RefNum)
	refIDs := strings.Split(p.RefIDs, "|")
	for i := range refIDs {
		if len(refIDs[i]) == 0 {
			continue
		}

		id := com.StrTo(refIDs[i][1:]).MustInt64()
		if pinfo, _ := GetPkgInfoById(id); pinfo != nil {
			pinfo.Name = path.Base(pinfo.ImportPath)
			pinfos = append(pinfos, pinfo)
		}
	}
	return pinfos
}

// PACKAGE_VER is modified when previously stored packages are invalid.
const PACKAGE_VER = 1

// PkgRef represents temporary reference information of a package.
type PkgRef struct {
	ID         int64  `xorm:"pk autoincr"`
	ImportPath string `xorm:"UNIQUE"`
	RefNum     int64
	RefIDs     string `xorm:"ref_ids LONGTEXT"`
}

func updatePkgRef(pid int64, refPath string) error {
	if base.IsGoRepoPath(refPath) ||
		refPath == "C" ||
		refPath[1] == '.' ||
		!base.IsValidRemotePath(refPath) {
		return nil
	}

	ref := new(PkgRef)
	has, err := x.Where("import_path=?", refPath).Get(ref)
	if err != nil {
		return fmt.Errorf("get PkgRef: %v", err)
	}

	queryStr := "$" + com.ToStr(pid) + "|"
	if !has {
		if _, err = x.Insert(&PkgRef{
			ImportPath: refPath,
			RefNum:     1,
			RefIDs:     queryStr,
		}); err != nil {
			return fmt.Errorf("insert PkgRef: %v", err)
		}
		return nil
	}

	i := strings.Index(ref.RefIDs, queryStr)
	if i > -1 {
		return nil
	}

	ref.RefIDs += queryStr
	ref.RefNum++
	_, err = x.Id(ref.ID).AllCols().Update(ref)
	return err
}

// checkRefs checks if given packages are still referencing this one.
func checkRefs(pinfo *PkgInfo) {
	var buf bytes.Buffer
	pinfo.RefNum = 0
	refIDs := strings.Split(pinfo.RefIDs, "|")
	for i := range refIDs {
		if len(refIDs[i]) == 0 {
			continue
		}

		fmt.Println(com.StrTo(refIDs[i][1:]).MustInt64())
		pkg, _ := GetPkgInfoById(com.StrTo(refIDs[i][1:]).MustInt64())
		if pkg == nil {
			continue
		}

		if strings.Index(pkg.ImportIDs, "$"+com.ToStr(pinfo.ID)+"|") == -1 {
			continue
		}

		buf.WriteString("$")
		buf.WriteString(com.ToStr(pkg.ID))
		buf.WriteString("|")
		pinfo.RefNum++
	}
	pinfo.RefIDs = buf.String()
}

// updateRef updates or crates corresponding reference import information.
func updateRef(pid int64, refPath string) (int64, error) {
	if len(refPath) == 0 {
		return 0, nil
	}

	pinfo, err := GetPkgInfo(refPath)
	if err != nil && pinfo == nil {
		if err == ErrPackageNotFound ||
			err == ErrPackageVersionTooOld {
			// Package hasn't existed yet, save to temporary place.
			return 0, updatePkgRef(pid, refPath)
		}
		return 0, fmt.Errorf("GetPkgInfo(%s): %v", refPath, err)
	}

	// Check if reference information has beed recorded.
	queryStr := "$" + com.ToStr(pid) + "|"
	i := strings.Index(pinfo.RefIDs, queryStr)
	if i > -1 {
		return pinfo.ID, nil
	}

	// Add new as needed.
	pinfo.RefIDs += queryStr
	pinfo.RefNum++
	_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
	return pinfo.ID, err
}

// SavePkgInfo saves package information.
func SavePkgInfo(pinfo *PkgInfo, updateRefs bool) (err error) {
	if len(pinfo.Synopsis) > 255 {
		pinfo.Synopsis = pinfo.Synopsis[:255]
	}

	pinfo.PkgVer = PACKAGE_VER

	switch {
	case pinfo.IsGaeRepo:
		pinfo.Priority = 70
	case pinfo.IsGoSubrepo:
		pinfo.Priority = 80
	case pinfo.IsGoRepo:
		pinfo.Priority = 99
	}

	// When package is not created, there is no ID so check will certainly fail.
	var ignoreCheckRefs bool

	// Create or update package info itself.
	// Note(Unknwon): do this because we need ID field later.
	if pinfo.ID == 0 {
		ignoreCheckRefs = true
		pinfo.Views = 1

		// First time created, check PkgRef.
		ref := new(PkgRef)
		has, err := x.Where("import_path=?", pinfo.ImportPath).Get(ref)
		if err != nil {
			return fmt.Errorf("get PkgRef: %v", err)
		} else if has {
			pinfo.RefNum = ref.RefNum
			pinfo.RefIDs = ref.RefIDs
			if _, err = x.Id(ref.ID).Delete(ref); err != nil {
				return fmt.Errorf("delete PkgRef: %v", err)
			}
		}

		_, err = x.Insert(pinfo)
	} else {
		_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
	}
	if err != nil {
		return fmt.Errorf("update package info: %v", err)
	}

	// Update package import references.
	// Note(Unknwon): I just don't see the value of who imports STD
	//	when you don't even import and uses what objects.
	if updateRefs && !pinfo.IsGoRepo {
		var buf bytes.Buffer
		paths := strings.Split(pinfo.ImportPaths, "|")
		for i := range paths {
			if base.IsGoRepoPath(paths[i]) {
				continue
			}

			refID, err := updateRef(pinfo.ID, paths[i])
			if err != nil {
				return fmt.Errorf("updateRef: %v", err)
			} else if refID == 0 {
				continue
			}
			buf.WriteString("$")
			buf.WriteString(com.ToStr(refID))
			buf.WriteString("|")
		}
		pinfo.ImportIDs = buf.String()

		if !ignoreCheckRefs {
			// Check packages who import this is still importing.
			checkRefs(pinfo)
		}
		_, err = x.Id(pinfo.ID).AllCols().Update(pinfo)
		return err
	}
	return nil
}

// GetPkgInfo returns package information by given import path.
func GetPkgInfo(importPath string) (*PkgInfo, error) {
	if len(importPath) == 0 {
		return nil, ErrEmptyPackagePath
	}

	pinfo := new(PkgInfo)
	has, err := x.Where("import_path=?", importPath).Get(pinfo)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, ErrPackageNotFound
	} else if pinfo.PkgVer < PACKAGE_VER {
		pinfo.Etag = ""
		return pinfo, ErrPackageVersionTooOld
	}

	if !com.IsFile(pinfo.JSPath()) {
		pinfo.Etag = ""
		return pinfo, ErrPackageVersionTooOld
	}

	return pinfo, nil
}

// GetSubPkgs returns sub-projects by given sub-directories.
func GetSubPkgs(importPath string, dirs []string) []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, len(dirs))
	for _, dir := range dirs {
		if len(dir) == 0 {
			continue
		}

		fullPath := importPath + "/" + dir
		if pinfo, err := GetPkgInfo(fullPath); err == nil {
			pinfo.Name = dir
			pinfos = append(pinfos, pinfo)
		} else {
			pinfos = append(pinfos, &PkgInfo{
				Name:       dir,
				ImportPath: fullPath,
			})
		}
	}
	return pinfos
}

// GetPkgInfosByPaths returns a list of packages by given import paths.
func GetPkgInfosByPaths(paths []string) []*PkgInfo {
	pinfos := make([]*PkgInfo, 0, len(paths))
	for _, p := range paths {
		if len(p) == 0 {
			continue
		}

		if pinfo, err := GetPkgInfo(p); err == nil {
			pinfo.Name = path.Base(p)
			pinfos = append(pinfos, pinfo)
		} else {
			pinfos = append(pinfos, &PkgInfo{
				Name:       path.Base(p),
				ImportPath: p,
			})
		}
	}
	return pinfos
}

// GetPkgInfoById returns package information by given ID.
func GetPkgInfoById(id int64) (*PkgInfo, error) {
	pinfo := new(PkgInfo)
	has, err := x.Id(id).Get(pinfo)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, ErrPackageNotFound
	} else if pinfo.PkgVer < PACKAGE_VER {
		return pinfo, ErrPackageVersionTooOld
	}

	if !com.IsFile(pinfo.JSPath()) {
		return pinfo, ErrPackageVersionTooOld
	}

	return pinfo, nil
}

// GetPkgInfosByIDs returns a list of package info by given IDs.
func GetPkgInfosByIDs(ids []int64) ([]*PkgInfo, error) {
	if len(ids) == 0 {
		return []*PkgInfo{}, nil
	}

	pkgInfos := make([]*PkgInfo, 0, len(ids))
	return pkgInfos, x.Where("id > 0").In("id", base.Int64sToStrings(ids)).Find(&pkgInfos)
}

func getRepos(trueCondition string) ([]*PkgInfo, error) {
	pkgs := make([]*PkgInfo, 0, 100)
	return pkgs, x.Desc("views").Where(trueCondition+"=?", true).Find(&pkgs)
}

func GetGoRepos() ([]*PkgInfo, error) {
	return getRepos("is_go_repo")
}

func GetGoSubepos() ([]*PkgInfo, error) {
	return getRepos("is_go_subrepo")
}

func GetGAERepos() ([]*PkgInfo, error) {
	return getRepos("is_gae_repo")
}

// SearchPkgInfo searches package information by given keyword.
func SearchPkgInfo(limit int, keyword string) ([]*PkgInfo, error) {
	if len(keyword) == 0 {
		return nil, nil
	}
	pkgs := make([]*PkgInfo, 0, limit)
	return pkgs, x.Limit(limit).Desc("priority").Desc("stars").Desc("views").Where("import_path like ?", "%"+keyword+"%").Find(&pkgs)
}

func DeletePackageByPath(importPath string) error {
	_, err := x.Delete(&PkgInfo{ImportPath: importPath})
	return err
}
<|endoftext|>


<commit_before>package manifest

import (
	"errors"
	"strconv"
	"testing"

	"github.com/bpicode/fritzctl/fritz"
	"github.com/stretchr/testify/assert"
)

type fritzApiAlwaysSuccess struct {
	devices fritz.Devicelist
}

// ListDevices always succeeds.
func (f *fritzApiAlwaysSuccess) ListDevices() (*fritz.Devicelist, error) {
	return &f.devices, nil
}

// NameToAinTable always succeeds.
func (f *fritzApiAlwaysSuccess) NameToAinTable() (map[string]string, error) {
	return make(map[string]string), nil
}

// ListDevices always succeeds.
func (f *fritzApiAlwaysSuccess) SwitchOn(ain string) (string, error) {
	return "1", nil
}

// SwitchOff always succeeds.
func (f *fritzApiAlwaysSuccess) SwitchOff(ain string) (string, error) {
	return "0", nil
}

// Toggle always succeeds.
func (f *fritzApiAlwaysSuccess) Toggle(ain string) (string, error) {
	return "1", nil
}

// ApplyTemperature always succeeds.
func (f *fritzApiAlwaysSuccess) ApplyTemperature(value float64, ain string) (string, error) {
	return strconv.FormatFloat(value*2.0, 'f', -1, 64), nil
}

// TestApplyViaAha tests the http interface applier.
func TestApplyViaAha(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysSuccess{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 17.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.NoError(t, err)
}

type fritzApiAlwaysError struct {
	devices fritz.Devicelist
}

// ListDevices always returns an error.
func (f *fritzApiAlwaysError) ListDevices() (*fritz.Devicelist, error) {
	return &f.devices, errors.New("That didn't work")
}

// NameToAinTable always returns an error.
func (f *fritzApiAlwaysError) NameToAinTable() (map[string]string, error) {
	return make(map[string]string), nil
}

// SwitchOn always returns an error.
func (f *fritzApiAlwaysError) SwitchOn(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// SwitchOff always returns an error.
func (f *fritzApiAlwaysError) SwitchOff(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// Toggle always returns an error.
func (f *fritzApiAlwaysError) Toggle(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// ApplyTemperature always returns an error.
func (f *fritzApiAlwaysError) ApplyTemperature(value float64, ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// TestApplyViaAhaErrorByThermostat tests the http interface applier.
func TestApplyViaAhaErrorByThermostat(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 17.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.Error(t, err)
}

// TestApplyViaAhaErrorBySwitch tests the http interface applier.
func TestApplyViaAhaErrorBySwitch(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.Error(t, err)
}

// TestApplyViaAhaErrorBySwitch tests the http interface applier.
func TestApplyViaAhaErrorByMalformedPlan(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "CCCCC", State: true}},
			Thermostats: []Thermostat{{Name: "YYYYYY", Temperature: 20.5}},
		})
	assert.Error(t, err)
}
<commit_msg>add more tests<commit_after>package manifest

import (
	"errors"
	"strconv"
	"testing"

	"github.com/bpicode/fritzctl/fritz"
	"github.com/stretchr/testify/assert"
)

type fritzApiAlwaysSuccess struct {
	devices fritz.Devicelist
}

// ListDevices always succeeds.
func (f *fritzApiAlwaysSuccess) ListDevices() (*fritz.Devicelist, error) {
	return &f.devices, nil
}

// NameToAinTable always succeeds.
func (f *fritzApiAlwaysSuccess) NameToAinTable() (map[string]string, error) {
	return make(map[string]string), nil
}

// ListDevices always succeeds.
func (f *fritzApiAlwaysSuccess) SwitchOn(ain string) (string, error) {
	return "1", nil
}

// SwitchOff always succeeds.
func (f *fritzApiAlwaysSuccess) SwitchOff(ain string) (string, error) {
	return "0", nil
}

// Toggle always succeeds.
func (f *fritzApiAlwaysSuccess) Toggle(ain string) (string, error) {
	return "1", nil
}

// ApplyTemperature always succeeds.
func (f *fritzApiAlwaysSuccess) ApplyTemperature(value float64, ain string) (string, error) {
	return strconv.FormatFloat(value*2.0, 'f', -1, 64), nil
}

// TestApplyViaAha tests the http interface applier.
func TestApplyViaAha(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysSuccess{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 17.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.NoError(t, err)
}

// TestApplyViaAhaLargeSystem tests the http interface applier.
func TestApplyViaAhaLargeSystem(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysSuccess{})
	err := applier.Apply(
		&Plan{
			Switches: []Switch{
				{Name: "s1", State: true},
				{Name: "s2", State: true},
				{Name: "s3", State: true},
				{Name: "s4", State: false},
				{Name: "s5", State: false},
				{Name: "s6", State: true},
				{Name: "s7", State: true},
				{Name: "s8", State: true},
				{Name: "s9", State: false},
				{Name: "s10", State: true},
				{Name: "s11", State: true},
				{Name: "s12", State: false},
				{Name: "s13", State: false},
			},
			Thermostats: []Thermostat{
				{Name: "t1", Temperature: 17.5},
				{Name: "t2", Temperature: 18.5},
				{Name: "t3", Temperature: 19.5},
				{Name: "t4", Temperature: 21.5},
				{Name: "t5", Temperature: 22.5},
				{Name: "t6", Temperature: 23.0},
				{Name: "t7", Temperature: 34.0},
				{Name: "t8", Temperature: 26.0},
				{Name: "t9", Temperature: 27.5},
			},
		},
		&Plan{
			Switches: []Switch{
				{Name: "s1", State: false},
				{Name: "s2", State: false},
				{Name: "s3", State: true},
				{Name: "s4", State: true},
				{Name: "s5", State: true},
				{Name: "s6", State: false},
				{Name: "s7", State: false},
				{Name: "s8", State: true},
				{Name: "s9", State: true},
				{Name: "s10", State: true},
				{Name: "s11", State: false},
				{Name: "s12", State: false},
				{Name: "s13", State: true},
			},
			Thermostats: []Thermostat{
				{Name: "t1", Temperature: 27.5},
				{Name: "t2", Temperature: 19.5},
				{Name: "t3", Temperature: 17.5},
				{Name: "t4", Temperature: 25.5},
				{Name: "t5", Temperature: 21.5},
				{Name: "t6", Temperature: 24.0},
				{Name: "t7", Temperature: 24.0},
				{Name: "t8", Temperature: 16.0},
				{Name: "t9", Temperature: 17.5},
			},
		})
	assert.NoError(t, err)
}

type fritzApiAlwaysError struct {
	devices fritz.Devicelist
}

// ListDevices always returns an error.
func (f *fritzApiAlwaysError) ListDevices() (*fritz.Devicelist, error) {
	return &f.devices, errors.New("That didn't work")
}

// NameToAinTable always returns an error.
func (f *fritzApiAlwaysError) NameToAinTable() (map[string]string, error) {
	return make(map[string]string), nil
}

// SwitchOn always returns an error.
func (f *fritzApiAlwaysError) SwitchOn(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// SwitchOff always returns an error.
func (f *fritzApiAlwaysError) SwitchOff(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// Toggle always returns an error.
func (f *fritzApiAlwaysError) Toggle(ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// ApplyTemperature always returns an error.
func (f *fritzApiAlwaysError) ApplyTemperature(value float64, ain string) (string, error) {
	return "", errors.New("That didn't work")
}

// TestApplyViaAhaErrorByThermostat tests the http interface applier.
func TestApplyViaAhaErrorByThermostat(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 17.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.Error(t, err)
}

// TestApplyViaAhaErrorBySwitch tests the http interface applier.
func TestApplyViaAhaErrorBySwitch(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "s", State: true}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		})
	assert.Error(t, err)
}

// TestApplyViaAhaErrorBySwitch tests the http interface applier.
func TestApplyViaAhaErrorByMalformedPlan(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches:    []Switch{{Name: "s", State: false}},
			Thermostats: []Thermostat{{Name: "t", Temperature: 20.5}},
		},
		&Plan{
			Switches:    []Switch{{Name: "CCCCC", State: true}},
			Thermostats: []Thermostat{{Name: "YYYYYY", Temperature: 20.5}},
		})
	assert.Error(t, err)
}

// TestApplyViaAhaLargeSystemWithErrors tests the http interface applier.
func TestApplyViaAhaLargeSystemWithErrors(t *testing.T) {
	applier := AhaApiApplier(&fritzApiAlwaysError{})
	err := applier.Apply(
		&Plan{
			Switches: []Switch{
				{Name: "s1", State: true},
				{Name: "s2", State: true},
				{Name: "s3", State: true},
				{Name: "s4", State: false},
				{Name: "s5", State: false},
				{Name: "s6", State: true},
				{Name: "s7", State: true},
				{Name: "s8", State: true},
				{Name: "s9", State: false},
				{Name: "s10", State: true},
				{Name: "s11", State: true},
				{Name: "s12", State: false},
				{Name: "s13", State: false},
			},
			Thermostats: []Thermostat{
				{Name: "t1", Temperature: 17.5},
				{Name: "t2", Temperature: 18.5},
				{Name: "t3", Temperature: 19.5},
				{Name: "t4", Temperature: 21.5},
				{Name: "t5", Temperature: 22.5},
				{Name: "t6", Temperature: 23.0},
				{Name: "t7", Temperature: 34.0},
				{Name: "t8", Temperature: 26.0},
				{Name: "t9", Temperature: 27.5},
			},
		},
		&Plan{
			Switches: []Switch{
				{Name: "s1", State: false},
				{Name: "s2", State: false},
				{Name: "s3", State: true},
				{Name: "s4", State: true},
				{Name: "s5", State: true},
				{Name: "s6", State: false},
				{Name: "s7", State: false},
				{Name: "s8", State: true},
				{Name: "s9", State: true},
				{Name: "s10", State: true},
				{Name: "s11", State: false},
				{Name: "s12", State: false},
				{Name: "s13", State: true},
			},
			Thermostats: []Thermostat{
				{Name: "t1", Temperature: 27.5},
				{Name: "t2", Temperature: 19.5},
				{Name: "t3", Temperature: 17.5},
				{Name: "t4", Temperature: 25.5},
				{Name: "t5", Temperature: 21.5},
				{Name: "t6", Temperature: 24.0},
				{Name: "t7", Temperature: 24.0},
				{Name: "t8", Temperature: 16.0},
				{Name: "t9", Temperature: 17.5},
			},
		})
	assert.Error(t, err)
}
<|endoftext|>


<commit_before>package models

import (
	"bytes"
	"net/url"
	"time"

	"fmt"

	"github.com/disintegration/imaging"
	"github.com/go-pg/pg"
	"github.com/go-pg/pg/orm"
	"github.com/harrisbaird/dailyteedeals/config"
	"github.com/harrisbaird/dailyteedeals/utils"
)

var imageTypes []utils.Transform

type ImageType int

func (t ImageType) Transform() utils.Transform {
	return imageTypes[int(t)]
}

func imageIota(t utils.Transform) ImageType {
	imageTypes = append(imageTypes, t)
	return ImageType(len(imageTypes) - 1)
}

var (
	OriginalImageType = imageIota(utils.Transform{Format: imaging.PNG, MimeType: "image/png", Path: "original/%d.png"})
	SmallImageType    = imageIota(utils.Transform{Format: imaging.JPEG, MimeType: "image/jpeg", Size: 300, Path: "thumbs/%d/300.jpg"})
	LargeImageType    = imageIota(utils.Transform{Format: imaging.JPEG, MimeType: "image/jpeg", Size: 1200, Path: "thumbs/%d/1200.jpg"})
)

type Product struct {
	ID              int
	DesignID        int
	SiteID          int
	Slug            string `sql:",notnull"`
	URL             string
	Active          bool                              `sql:",notnull"`
	Deal            bool                              `sql:",notnull"`
	LastChance      bool                              `sql:",notnull"`
	Tags            []string                          `pg:",array" sql:"tags,DEFAULT:'{}',notnull"`
	Prices          map[string]string                 `pg:",hstore"`
	ConvertedPrices map[string]utils.ApproximatePrice `sql:"-"`
	ImageBackground string
	ImageUpdatedAt  time.Time
	ExpiresAt       pg.NullTime
	ActiveAt        pg.NullTime

	Design *Design
	Site   *Site
}

const updateImagesEvery = 7 * 24 * time.Hour

// ActiveDeals queries the database for currently active deals
// and eager loads related models.
// It returns a `model.Product` slice and any error encountered.
func ActiveDeals(db orm.DB) ([]*Product, error) {
	var products []*Product
	err := db.Model(&products).
		Column("product.*", "Site", "Design", "Design.Artist").
		Where("product.active=? AND product.deal=?", true, true).
		Order("site.display_order ASC", "product.site_id ASC", "product.last_chance ASC", "product.slug ASC").
		Select()
	return products, err
}

func FindProductBySlug(db orm.DB, slug string) (*Product, error) {
	var product Product
	err := db.Model(&product).
		Column("product.*", "Site", "Design", "Design.Artist").
		Where("product.slug=?", slug).
		First()
	return &product, err
}

// MarkProductsInactive sets products belonging to a site as inactive.
// It either does all deals or non-deals.
func MarkProductsInactive(db orm.DB, siteID int, deal bool) error {
	_, err := db.Exec("UPDATE products SET active=? WHERE site_id=? AND deal=?", false, siteID, deal)
	return err
}

func (p *Product) GoURL() string {
	return fmt.Sprintf("https://go.dailyteedeals.com/%s", p.Slug)
}

func (p *Product) BuyURL(db orm.DB) (string, error) {
	var site Site
	err := db.Model(&site).Where("id=?", p.SiteID).First()

	if err != nil || site.AffiliateURL == "" {
		return p.URL, err
	}

	return fmt.Sprintf(site.AffiliateURL, url.QueryEscape(p.URL)), nil
}

func (p *Product) ImageURL(imageType ImageType) string {
	transform := imageType.Transform()
	return fmt.Sprintf("https://%s/"+transform.Path+"?v=%d", config.App.DomainImages,
		p.ID, p.ImageUpdatedAt.Unix())
}

func (p *Product) SmallImageURL() string {
	return p.ImageURL(SmallImageType)
}

func (p *Product) LargeImageURL() string {
	return p.ImageURL(LargeImageType)
}

func (p *Product) UpdateImageIfExpired(db orm.DB, minioConn *utils.MinioConnection, url string) error {
	if time.Since(p.ImageUpdatedAt) < updateImagesEvery {
		return nil
	}

	return p.UpdateImage(db, minioConn, url)
}

func (p *Product) UpdateImage(db orm.DB, minioConn *utils.MinioConnection, url string) error {
	imageFile, err := utils.HTTPGetToTempfile(url)
	if err != nil {
		return err
	}

	image, err := imaging.Open(imageFile.Name())
	if err != nil {
		return err
	}

	bgColor := utils.FindBackgroundColor(image)
	for _, transform := range imageTypes {
		thumb := utils.TransformImage(image, transform, bgColor)
		imageData := new(bytes.Buffer)
		imaging.Encode(imageData, thumb, transform.Format)
		_, err := minioConn.Client.PutObject(minioConn.Bucket, fmt.Sprintf(transform.Path, p.ID), imageData, transform.MimeType)
		if err != nil {
			return err
		}
	}

	p.ImageBackground = utils.ColorToHex(bgColor)
	p.ImageUpdatedAt = time.Now()
	return db.Update(p)
}

func (p *Product) BeforeInsert(db orm.DB) error {
	return p.normalize(db)
}

func (p *Product) BeforeUpdate(db orm.DB) error {
	return p.normalize(db)
}

func (p *Product) AfterQuery(db orm.DB) error {
	p.ConvertedPrices = utils.ConvertPrices(p.Prices)
	return nil
}

func (p *Product) normalize(db orm.DB) error {
	if p.Slug == "" {
		err := p.updateProductSlug(db)
		if err != nil {
			return err
		}
	}
	p.Tags = NormalizeTags(p.Tags)
	return nil
}

func (p *Product) updateProductSlug(db orm.DB) error {
	design := Design{ID: p.DesignID}
	err := db.Select(&design)
	if err != nil {
		return err
	}

	site := Site{ID: p.SiteID}
	err = db.Select(&site)
	if err != nil {
		return err
	}

	p.Slug = MakeSlug(design.Name + " on " + site.Name)
	return nil
}
<commit_msg>Cleanup product<commit_after>package models

import (
	"bytes"
	"net/url"
	"time"

	"fmt"

	"github.com/disintegration/imaging"
	"github.com/go-pg/pg"
	"github.com/go-pg/pg/orm"
	"github.com/harrisbaird/dailyteedeals/config"
	"github.com/harrisbaird/dailyteedeals/utils"
)

var imageTypes []utils.Transform

type ImageType int

func (t ImageType) Transform() utils.Transform {
	return imageTypes[int(t)]
}

func imageIota(t utils.Transform) ImageType {
	imageTypes = append(imageTypes, t)
	return ImageType(len(imageTypes) - 1)
}

var (
	OriginalImageType = imageIota(utils.Transform{Format: imaging.PNG, MimeType: "image/png", Path: "original/%d.png"})
	SmallImageType    = imageIota(utils.Transform{Format: imaging.JPEG, MimeType: "image/jpeg", Size: 300, Path: "thumbs/%d/300.jpg"})
	LargeImageType    = imageIota(utils.Transform{Format: imaging.JPEG, MimeType: "image/jpeg", Size: 1200, Path: "thumbs/%d/1200.jpg"})
)

type Product struct {
	ID              int
	DesignID        int
	SiteID          int
	Slug            string `sql:",notnull"`
	URL             string
	Active          bool                              `sql:",notnull"`
	Deal            bool                              `sql:",notnull"`
	LastChance      bool                              `sql:",notnull"`
	Tags            []string                          `pg:",array" sql:"tags,DEFAULT:'{}',notnull"`
	Prices          map[string]string                 `pg:",hstore"`
	ConvertedPrices map[string]utils.ApproximatePrice `sql:"-"`
	ImageBackground string
	ImageUpdatedAt  time.Time
	ExpiresAt       pg.NullTime
	ActiveAt        pg.NullTime

	Design *Design
	Site   *Site
}

const updateImagesEvery = 7 * 24 * time.Hour

// ActiveDeals queries the database for currently active deals
// and eager loads related models.
// It returns a `model.Product` slice and any error encountered.
func ActiveDeals(db orm.DB) ([]*Product, error) {
	var products []*Product
	err := db.Model(&products).
		Column("product.*", "Site", "Design", "Design.Artist").
		Where("product.active=? AND product.deal=?", true, true).
		Order("site.display_order ASC", "product.site_id ASC", "product.last_chance ASC", "product.slug ASC").
		Select()
	return products, err
}

func FindProductBySlug(db orm.DB, slug string) (*Product, error) {
	var product Product
	err := db.Model(&product).
		Column("product.*", "Site", "Design", "Design.Artist").
		Where("product.slug=?", slug).
		First()
	return &product, err
}

// MarkProductsInactive sets products belonging to a site as inactive.
// It either does all deals or non-deals.
func MarkProductsInactive(db orm.DB, siteID int, deal bool) error {
	_, err := db.Exec("UPDATE products SET active=? WHERE site_id=? AND deal=?", false, siteID, deal)
	return err
}

func (p *Product) GoURL() string {
	return fmt.Sprintf("https://go.dailyteedeals.com/%s", p.Slug)
}

func (p *Product) BuyURL(db orm.DB) (string, error) {
	var site Site
	err := db.Model(&site).Where("id=?", p.SiteID).First()

	if err != nil || site.AffiliateURL == "" {
		return p.URL, err
	}

	return fmt.Sprintf(site.AffiliateURL, url.QueryEscape(p.URL)), nil
}

func (p *Product) ImageURL(imageType ImageType) string {
	transform := imageType.Transform()
	return fmt.Sprintf("https://%s/"+transform.Path+"?v=%d", config.App.DomainImages,
		p.ID, p.ImageUpdatedAt.Unix())
}

func (p *Product) SmallImageURL() string {
	return p.ImageURL(SmallImageType)
}

func (p *Product) LargeImageURL() string {
	return p.ImageURL(LargeImageType)
}

func (p *Product) UpdateImageIfExpired(db orm.DB, minioConn *utils.MinioConnection, url string) error {
	if time.Since(p.ImageUpdatedAt) < updateImagesEvery {
		return nil
	}

	return p.UpdateImage(db, minioConn, url)
}

func (p *Product) UpdateImage(db orm.DB, minioConn *utils.MinioConnection, url string) error {
	imageFile, err := utils.HTTPGetToTempfile(url)
	if err != nil {
		return err
	}

	image, err := imaging.Open(imageFile.Name())
	if err != nil {
		return err
	}

	bgColor := utils.FindBackgroundColor(image)
	for _, transform := range imageTypes {
		thumb := utils.TransformImage(image, transform, bgColor)
		imageData := new(bytes.Buffer)
		imaging.Encode(imageData, thumb, transform.Format)
		if err := minioConn.PutObject(fmt.Sprintf(transform.Path, p.ID), imageData, transform.MimeType); err != nil {
			return err
		}
	}

	p.ImageBackground = utils.ColorToHex(bgColor)
	p.ImageUpdatedAt = time.Now()
	return db.Update(p)
}

func (p *Product) BeforeInsert(db orm.DB) error {
	return p.normalize(db)
}

func (p *Product) BeforeUpdate(db orm.DB) error {
	return p.normalize(db)
}

func (p *Product) AfterQuery(db orm.DB) error {
	p.ConvertedPrices = utils.ConvertPrices(p.Prices)
	return nil
}

func (p *Product) normalize(db orm.DB) error {
	if p.Slug == "" {
		err := p.updateProductSlug(db)
		if err != nil {
			return err
		}
	}
	p.Tags = NormalizeTags(p.Tags)
	return nil
}

func (p *Product) updateProductSlug(db orm.DB) error {
	design := Design{ID: p.DesignID}
	err := db.Select(&design)
	if err != nil {
		return err
	}

	site := Site{ID: p.SiteID}
	err = db.Select(&site)
	if err != nil {
		return err
	}

	p.Slug = MakeSlug(design.Name + " on " + site.Name)
	return nil
}
<|endoftext|>


<commit_before>package github

import (
	"github.com/google/go-github/github"
)

// Repository represents a single repository from github.
// This struct is a stripped down version of github.Repository.
// We only return the values we need here.
type Repository struct {
	StargazersCount *int `json:"stargazers_count,omitempty"`
}

// GetRepositoryDetails will retrieve details about the repository owner/repo from github.
func GetRepositoryDetails(owner, repo string) (*Repository, error) {
	client := github.NewClient(nil)
	repository, _, err := client.Repositories.Get(owner, repo)
	if repository == nil {
		return nil, err
	}

	r := &Repository{
		StargazersCount: repository.StargazersCount,
	}
	return r, err
}
<commit_msg>Upgraded github-go library and make use of the context<commit_after>package github

import (
	"context"

	"github.com/google/go-github/github"
)

// Repository represents a single repository from github.
// This struct is a stripped down version of github.Repository.
// We only return the values we need here.
type Repository struct {
	StargazersCount *int `json:"stargazers_count,omitempty"`
}

// GetRepositoryDetails will retrieve details about the repository owner/repo from github.
func GetRepositoryDetails(owner, repo string) (*Repository, error) {
	client := github.NewClient(nil)
	repository, _, err := client.Repositories.Get(context.Background(), owner, repo)
	if repository == nil {
		return nil, err
	}

	r := &Repository{
		StargazersCount: repository.StargazersCount,
	}
	return r, err
}
<|endoftext|>