<commit_before>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/joeshaw/envdecode"
	"gopkg.in/mailgun/mailgun-go.v1"
)

const (
	mailDomain  = "list.brandur.org"
	fromAddress = "Brandur <brandur@brandur.org>"
)

// Conf contains configuration information for the command. It's extracted from
// environment variables.
type Conf struct {
	// MailgunAPIKey is a key for Mailgun used to send email.
	MailgunAPIKey string `env:"MAILGUN_API_KEY,required"`
}

// Left as a global for now for the sake of convenience, but it's not used in
// very many places and can probably be refactored as a local if desired.
var conf Conf

func renderAndSend(records [][]string, live bool) error {
	mg := mailgun.NewMailgun(mailDomain, conf.MailgunAPIKey, "")

	for _, record := range records {
		// skip empty lines
		if len(record) == 0 {
			continue
		}

		if len(record) < 2 {
			return fmt.Errorf("Record less than 2-width: %v", record)
		}

		name := record[0]
		recipient := record[1]

		subject := "I'm subscribing you to my newsletter"
		body := fmt.Sprintf(`%s,

One thing I've realized over the last few years is that I
don't do a very good job of keeping up with old friends and
family. I don't really use Facebook, link only technical
writing on on Twitter, and the new age social media
platforms like Instagram and Snapchat are well beyond me,
so I'm not even staying in touch in a passive sense.

On a recent trip to Portland I was thinking about this
problem and what I might be able to do to about it, and as
I was walking the city's eclectic streets, I had an idea:
an email newsletter. Each issue will be a short compilation
of stories, photographs, and ideas. It will remind me to
send something to you, and hopefully remind you to send
something back.

In case you have a healthy fear of inbox overload, the
bursts will be pretty infrequent; I'll be competing with
total solar eclipses on time scale.

(This email is not the newsletter, but) I'm about to send
its first issue, and I've added you to the list to receive
it. If you don't want it, either reply to me here saying
so, or wait until I send it and click the very conspicuous
unsubscribe link (I won't get notified on an unsubscribe,
and even if I did, I wouldn't take it personally).

Thanks, and take care!

Brandur`,
			name,
		)

		if live {
			message := mailgun.NewMessage(fromAddress, subject, body, recipient)
			resp, _, err := mg.Send(message)
			if err != nil {
				log.Fatal(err)
			}
			log.Printf(`Sent to: %s (response: "%s")`, recipient, resp)
		} else {
			fmt.Printf("To: %v <%v>\n", name, recipient)
			fmt.Printf("Subject: %v\n\n", subject)
			fmt.Printf("%v\n---\n\n", body)
		}
	}

	return nil
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [-live] <recipient_file>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	live := flag.Bool("live", false,
		"Send to list (as opposed to dry run)")
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
	}

	err := envdecode.Decode(&conf)
	if err != nil {
		log.Fatal(err)
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	r := csv.NewReader(f)
	r.Comment = '#'

	records, err := r.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	err = renderAndSend(records, *live)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Change wording around<commit_after>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/joeshaw/envdecode"
	"gopkg.in/mailgun/mailgun-go.v1"
)

const (
	mailDomain  = "list.brandur.org"
	fromAddress = "Brandur <brandur@brandur.org>"
)

// Conf contains configuration information for the command. It's extracted from
// environment variables.
type Conf struct {
	// MailgunAPIKey is a key for Mailgun used to send email.
	MailgunAPIKey string `env:"MAILGUN_API_KEY,required"`
}

// Left as a global for now for the sake of convenience, but it's not used in
// very many places and can probably be refactored as a local if desired.
var conf Conf

func renderAndSend(records [][]string, live bool) error {
	mg := mailgun.NewMailgun(mailDomain, conf.MailgunAPIKey, "")

	for _, record := range records {
		// skip empty lines
		if len(record) == 0 {
			continue
		}

		if len(record) < 2 {
			return fmt.Errorf("Record less than 2-width: %v", record)
		}

		name := record[0]
		recipient := record[1]

		subject := "A newsletter"
		body := fmt.Sprintf(`%s,

One thing I've realized over the last few years is that I
don't do a very good job of keeping up with old friends and
family. I don'really use Facebook, and the new age social
media platforms of the Instagram and Snapchat variety are
well beyond me. Also, like any good millenial, I almost
never pick up the phone :)

On a recent trip I was thinking about what to do about it,
and came up with the idea of writing a very occasional
newsletter to people I know. The intent is for each one to
be a short compilation of stories, photographs, and ideas.
It'll remind me to send something to you, and hopefully
remind you to send something back.

This is just a quick note that I'm going to add you to the
receipt list. In case you have a healthy fear of inbox
overload, the bursts will be pretty infrequent; I'll be
competing with total solar eclipses on time scale. If
that's still not good enough, either reply to me here
saying so, or wait until I send it and just click the very
conspicuous "unsubscribe" link and you'll never get one
again (I won't get notified on an unsubscribe, and even if
I did, I wouldn't take it personally).

I hope everything is well!

Brandur`,
			name,
		)

		if live {
			message := mailgun.NewMessage(fromAddress, subject, body, recipient)
			resp, _, err := mg.Send(message)
			if err != nil {
				log.Fatal(err)
			}
			log.Printf(`Sent to: %s (response: "%s")`, recipient, resp)
		} else {
			fmt.Printf("To: %v <%v>\n", name, recipient)
			fmt.Printf("Subject: %v\n\n", subject)
			fmt.Printf("%v\n---\n\n", body)
		}
	}

	return nil
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [-live] <recipient_file>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	live := flag.Bool("live", false,
		"Send to list (as opposed to dry run)")
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
	}

	err := envdecode.Decode(&conf)
	if err != nil {
		log.Fatal(err)
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	r := csv.NewReader(f)
	r.Comment = '#'

	records, err := r.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	err = renderAndSend(records, *live)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import "github.com/dynport/urknall"

func NewSyslogNg(version string) *SyslogNg {
	return &SyslogNg{Version: version}
}

const syslogNgRestart = "{ status syslog-ng | grep running && restart syslog-ng; } || start syslog-ng"

type SyslogNg struct {
	Version string `urknall:"default=3.5.1"`
}

func (ng *SyslogNg) url() string {
	return "http://www.balabit.com/downloads/files/syslog-ng/open-source-edition/{{ .Version }}/source/syslog-ng_{{ .Version }}.tar.gz"
}

func (ng *SyslogNg) Package(r *urknall.Runlist) {
	r.Add(
		InstallPackages("build-essential", "libevtlog-dev", "pkg-config", "libglib2.0-dev"),
		DownloadAndExtract(ng.url(), "/opt/src"),
		And(
			"cd {{ .InstallPath }}",
			"./configure",
			"make",
			"make install",
		),
		WriteFile("/etc/init/syslog-ng.conf", syslogNgUpstart, "root", 0644),
	)
}

func (ng *SyslogNg) InstallPath() string {
	return "/opt/src/syslog-ng-{{ .Version }}"
}

const syslogNgUpstart = `# syslog-ng - system logging daemon
#
# syslog-ng is an replacement for the traditionala syslog daemon, logging messages from applications

description     "system logging daemon"

start on filesystem
stop on runlevel [06]

env LD_LIBRARY_PATH=/usr/local/lib

respawn

exec syslog-ng -F
`

type SyslogNgReceiver struct {
	Version  string `urknall:"default=3.5.1"`
	LogsRoot string `urknall:"default=/var/log/hourly"`
	AmqpHost string
}

func (p *SyslogNgReceiver) Package(r *urknall.Runlist) {
	r.Add(
		&SyslogNg{Version: p.Version},
		WriteFile("/usr/local/etc/syslog-ng.conf", syslogReceiver, "root", 0644),
		CreateHourlySymlinks{Root: p.LogsRoot},
		syslogNgRestart,
	)
}

type SyslogNgSender struct {
	Receiver string
	Version  string `urknall:"default=3.5"`
}

func (s *SyslogNgSender) Package(r *urknall.Runlist) {
	r.Add(
		&SyslogNg{Version: s.Version},
		WriteFile("/usr/local/etc/syslog-ng.conf", syslogNgSender, "root", 0644),
		syslogNgRestart,
	)
}

const syslogNgSender = `@version: {{ .Version }}
@include "scl.conf"

options {
  chain_hostnames(0);
  keep_hostname(yes);
  time_reopen(10);
  time_reap(360);
  log_fifo_size(2048);
  create_dirs(yes);
  perm(0640);
  dir_perm(0755);
  use_dns(no);
  stats_freq(43200);
  frac_digits(6);
  ts_format(iso);
};

source s_network {
  udp(port(514));
  tcp(port(514));
};

source s_local {
    file("/proc/kmsg");
    unix-stream("/dev/log");
    internal();
};

destination d_syslog_tcp {
	syslog("{{ .Receiver }}" transport("tcp"));
};

log {
	source(s_local);
	source(s_network);
	destination(d_syslog_tcp);
};
`

type CreateHourlySymlinks struct {
	Root string `urknall:"default=/var/log/hourly"`
}

func (*CreateHourlySymlinks) Package(r *urknall.Runlist) {
	r.Add(
		Mkdir("/opt/scripts", "root", 0755),
		WriteFile("/opt/scripts/create_hourly_symlinks.sh", createHourlySymlinks, "root", 0755),
		WriteFile("/etc/cron.d/create_hourly_symlinks", "* * * * * root /opt/scripts/create_hourly_symlinks.sh 2>&1 | logger -i -t create_hourly_symlinks\n", "root", 0644),
	)
}

const createHourlySymlinks = `
#!/usr/bin/env bash
set -e

LOG_DIR={{ .Root }}
NOW=$LOG_DIR/$(date +"%Y/%m/%d/%Y-%m-%dT%H.log")
TODAY=$(dirname $NOW)

mkdir -p $TODAY
touch $NOW
chmod 0644 $NOW
ln -nfs $NOW $LOG_DIR/current
ln -nfs $TODAY $LOG_DIR/today
`

const syslogReceiver = `@version: {{ .Version }}
@include "scl.conf"

options {
  chain_hostnames(0);
  keep_hostname(yes);
  time_reopen(10);
  time_reap(360);
  log_fifo_size(2048);
  create_dirs(yes);
  perm(0640);
  dir_perm(0755);
  use_dns(no);
  stats_freq(43200);
  frac_digits(6);
  ts_format(iso);
};

source s_network {
  udp(port(514));
  tcp(port(514));
};

source s_local {
    file("/proc/kmsg");
    unix-stream("/dev/log");
    internal();
};

{{ with .AmqpHost }}
destination d_amqp {
  amqp(
      vhost("/")
      host("{{ . }}")
      port(5672)
      username("guest") # required option, no default
      password("guest") # required option, no default
      exchange("syslog")
      exchange_declare(yes)
      exchange_type("fanout")
      routing_key("$HOST.$PROGRAM.$PRIORITY")
      body("$S_ISODATE $HOST $PROGRAM.$PRIORITY[$PID]: $MSG\n")
      persistent(yes)
      frac_digits(6)
      value-pairs(
          scope("selected-macros" "nv-pairs" "sdata")
      )
  );
};
{{ end }}

destination d_file {
  file(
    "{{ .LogsRoot }}/$R_YEAR/$R_MONTH/$R_DAY/$R_YEAR-$R_MONTH-${R_DAY}T${R_HOUR}.log"
    template("$S_ISODATE $HOST $PROGRAM.$PRIORITY[$PID]: $MSG\n")
    template_escape(no)
    perm( 0644 )
    dir_perm( 0775 )
    frac_digits(6)
  );
};

log {
  source(s_local);
  source(s_network);
  {{ with .AmqpHost }}destination(d_amqp);{{ end }}
  destination(d_file);
};
`
<commit_msg>fix syslog receiver<commit_after>package main

import "github.com/dynport/urknall"

func NewSyslogNg(version string) *SyslogNg {
	return &SyslogNg{Version: version}
}

const syslogNgRestart = "{ status syslog-ng | grep running && restart syslog-ng; } || start syslog-ng"

type SyslogNg struct {
	Version string `urknall:"default=3.5.1"`
}

func (ng *SyslogNg) url() string {
	return "http://www.balabit.com/downloads/files/syslog-ng/open-source-edition/{{ .Version }}/source/syslog-ng_{{ .Version }}.tar.gz"
}

func (ng *SyslogNg) Package(r *urknall.Runlist) {
	r.Add(
		InstallPackages("build-essential", "libevtlog-dev", "pkg-config", "libglib2.0-dev"),
		DownloadAndExtract(ng.url(), "/opt/src"),
		And(
			"cd {{ .InstallPath }}",
			"./configure",
			"make",
			"make install",
		),
		WriteFile("/etc/init/syslog-ng.conf", syslogNgUpstart, "root", 0644),
	)
}

func (ng *SyslogNg) InstallPath() string {
	return "/opt/src/syslog-ng-{{ .Version }}"
}

const syslogNgUpstart = `# syslog-ng - system logging daemon
#
# syslog-ng is an replacement for the traditionala syslog daemon, logging messages from applications

description     "system logging daemon"

start on filesystem
stop on runlevel [06]

env LD_LIBRARY_PATH=/usr/local/lib

respawn

exec syslog-ng -F
`

type SyslogNgReceiver struct {
	Version  string `urknall:"default=3.5.1"`
	LogsRoot string `urknall:"default=/var/log/hourly"`
	AmqpHost string
}

func (p *SyslogNgReceiver) Package(r *urknall.Runlist) {
	r.Add(
		&SyslogNg{Version: p.Version},
		WriteFile("/usr/local/etc/syslog-ng.conf", syslogReceiver, "root", 0644),
		&CreateHourlySymlinks{Root: p.LogsRoot},
		syslogNgRestart,
	)
}

type SyslogNgSender struct {
	Receiver string
	Version  string `urknall:"default=3.5"`
}

func (s *SyslogNgSender) Package(r *urknall.Runlist) {
	r.Add(
		&SyslogNg{Version: s.Version},
		WriteFile("/usr/local/etc/syslog-ng.conf", syslogNgSender, "root", 0644),
		syslogNgRestart,
	)
}

const syslogNgSender = `@version: {{ .Version }}
@include "scl.conf"

options {
  chain_hostnames(0);
  keep_hostname(yes);
  time_reopen(10);
  time_reap(360);
  log_fifo_size(2048);
  create_dirs(yes);
  perm(0640);
  dir_perm(0755);
  use_dns(no);
  stats_freq(43200);
  frac_digits(6);
  ts_format(iso);
};

source s_network {
  udp(port(514));
  tcp(port(514));
};

source s_local {
    file("/proc/kmsg");
    unix-stream("/dev/log");
    internal();
};

destination d_syslog_tcp {
	syslog("{{ .Receiver }}" transport("tcp"));
};

log {
	source(s_local);
	source(s_network);
	destination(d_syslog_tcp);
};
`

type CreateHourlySymlinks struct {
	Root string `urknall:"default=/var/log/hourly"`
}

func (*CreateHourlySymlinks) Package(r *urknall.Runlist) {
	r.Add(
		Mkdir("/opt/scripts", "root", 0755),
		WriteFile("/opt/scripts/create_hourly_symlinks.sh", createHourlySymlinks, "root", 0755),
		WriteFile("/etc/cron.d/create_hourly_symlinks", "* * * * * root /opt/scripts/create_hourly_symlinks.sh 2>&1 | logger -i -t create_hourly_symlinks\n", "root", 0644),
	)
}

const createHourlySymlinks = `
#!/usr/bin/env bash
set -e

LOG_DIR={{ .Root }}
NOW=$LOG_DIR/$(date +"%Y/%m/%d/%Y-%m-%dT%H.log")
TODAY=$(dirname $NOW)

mkdir -p $TODAY
touch $NOW
chmod 0644 $NOW
ln -nfs $NOW $LOG_DIR/current
ln -nfs $TODAY $LOG_DIR/today
`

const syslogReceiver = `@version: {{ .Version }}
@include "scl.conf"

options {
  chain_hostnames(0);
  keep_hostname(yes);
  time_reopen(10);
  time_reap(360);
  log_fifo_size(2048);
  create_dirs(yes);
  perm(0640);
  dir_perm(0755);
  use_dns(no);
  stats_freq(43200);
  frac_digits(6);
  ts_format(iso);
};

source s_network {
  udp(port(514));
  tcp(port(514));
};

source s_local {
    file("/proc/kmsg");
    unix-stream("/dev/log");
    internal();
};

{{ with .AmqpHost }}
destination d_amqp {
  amqp(
      vhost("/")
      host("{{ . }}")
      port(5672)
      username("guest") # required option, no default
      password("guest") # required option, no default
      exchange("syslog")
      exchange_declare(yes)
      exchange_type("fanout")
      routing_key("$HOST.$PROGRAM.$PRIORITY")
      body("$S_ISODATE $HOST $PROGRAM.$PRIORITY[$PID]: $MSG\n")
      persistent(yes)
      frac_digits(6)
      value-pairs(
          scope("selected-macros" "nv-pairs" "sdata")
      )
  );
};
{{ end }}

destination d_file {
  file(
    "{{ .LogsRoot }}/$R_YEAR/$R_MONTH/$R_DAY/$R_YEAR-$R_MONTH-${R_DAY}T${R_HOUR}.log"
    template("$S_ISODATE $HOST $PROGRAM.$PRIORITY[$PID]: $MSG\n")
    template_escape(no)
    perm( 0644 )
    dir_perm( 0775 )
    frac_digits(6)
  );
};

log {
  source(s_local);
  source(s_network);
  {{ with .AmqpHost }}destination(d_amqp);{{ end }}
  destination(d_file);
};
`
<|endoftext|>


<commit_before>package base

import (
	"fmt"
	"io"
	"log"
	"path/filepath"

	"github.com/natefinch/lumberjack"
	"github.com/pkg/errors"
)

var (
	ErrInvalidLogFilePath   = errors.New("Invalid LogFilePath")
	ErrInvalidLoggingMaxAge = errors.New("Invalid MaxAge")

	maxAgeLimit             = 9999 // days
	defaultMaxSize          = 200  // megabytes
	defaultMaxAgeMultiplier = 2    // e.g. 90 minimum == 180 default maxAge
)

type FileLogger struct {
	Enabled bool

	logger *log.Logger
}

type FileLoggerConfig struct {
	Enabled  *bool             `json:",omitempty"` // Toggle for this log output
	Rotation logRotationConfig `json:",omitempty"` // Log rotation settings

	Output io.Writer `json:"-"` // Logger output. Defaults to os.Stderr. Can be overridden for testing purposes.
}

type logRotationConfig struct {
	MaxSize   *int `json:",omitempty"` // The maximum size in MB of the log file before it gets rotated.
	MaxAge    *int `json:",omitempty"` // The maximum number of days to retain old log files.
	LocalTime bool `json:",omitempty"` // If true, it uses the computer's local time to format the backup timestamp.
}

// NewFileLogger returms a new FileLogger from a config.
func NewFileLogger(config FileLoggerConfig, level LogLevel, logFilePath string, minAge int) (*FileLogger, error) {
	// validate and set defaults
	if err := config.init(level, logFilePath, minAge); err != nil {
		return nil, err
	}

	return &FileLogger{
		Enabled: *config.Enabled,
		logger:  log.New(config.Output, "", 0),
	}, nil
}

// shouldLog returns true if we can log.
func (l *FileLogger) shouldLog() bool {
	return l != nil && l.logger != nil &&
		// Check the log file is enabled
		l.Enabled
}

func (lfc *FileLoggerConfig) init(level LogLevel, logFilePath string, minAge int) error {
	if lfc == nil {
		return errors.New("nil LogFileConfig")
	}

	if lfc.Enabled == nil {
		// enable for all levels except debug by default
		lfc.Enabled = BoolPtr(level != LevelDebug)
	}

	if lfc.Rotation.MaxSize == nil {
		lfc.Rotation.MaxSize = &defaultMaxSize
	}

	if lfc.Rotation.MaxAge == nil {
		defaultMaxAge := minAge * defaultMaxAgeMultiplier
		lfc.Rotation.MaxAge = &defaultMaxAge
	} else if *lfc.Rotation.MaxAge < minAge {
		return fmt.Errorf("MaxAge for %s was set to %d which is below the minimum of %d", LogLevelName(level), *lfc.Rotation.MaxAge, minAge)
	} else if *lfc.Rotation.MaxAge > maxAgeLimit {
		return fmt.Errorf("MaxAge for %s was set to %d which is above the maximum of %d", LogLevelName(level), *lfc.Rotation.MaxAge, maxAgeLimit)
	}

	if lfc.Output == nil {
		lfc.Output = newLumberjackOutput(
			filepath.Join(filepath.FromSlash(logFilePath), "sg_"+LogLevelName(level)+".log"),
			*lfc.Rotation.MaxSize,
			*lfc.Rotation.MaxAge,
		)
	}

	return nil
}

func newLumberjackOutput(filename string, maxSize, maxAge int) *lumberjack.Logger {
	return &lumberjack.Logger{
		Filename: filename,
		MaxSize:  maxSize,
		MaxAge:   maxAge,
		Compress: true,
	}
}
<commit_msg>Add support for zero meaning disabled in the log rotation maxAge field (#3463)<commit_after>package base

import (
	"fmt"
	"io"
	"log"
	"path/filepath"

	"github.com/natefinch/lumberjack"
	"github.com/pkg/errors"
)

var (
	ErrInvalidLogFilePath   = errors.New("Invalid LogFilePath")
	ErrInvalidLoggingMaxAge = errors.New("Invalid MaxAge")

	maxAgeLimit             = 9999 // days
	defaultMaxSize          = 200  // megabytes
	defaultMaxAgeMultiplier = 2    // e.g. 90 minimum == 180 default maxAge
)

type FileLogger struct {
	Enabled bool

	logger *log.Logger
}

type FileLoggerConfig struct {
	Enabled  *bool             `json:",omitempty"` // Toggle for this log output
	Rotation logRotationConfig `json:",omitempty"` // Log rotation settings

	Output io.Writer `json:"-"` // Logger output. Defaults to os.Stderr. Can be overridden for testing purposes.
}

type logRotationConfig struct {
	MaxSize   *int `json:",omitempty"` // The maximum size in MB of the log file before it gets rotated.
	MaxAge    *int `json:",omitempty"` // The maximum number of days to retain old log files.
	LocalTime bool `json:",omitempty"` // If true, it uses the computer's local time to format the backup timestamp.
}

// NewFileLogger returms a new FileLogger from a config.
func NewFileLogger(config FileLoggerConfig, level LogLevel, logFilePath string, minAge int) (*FileLogger, error) {
	// validate and set defaults
	if err := config.init(level, logFilePath, minAge); err != nil {
		return nil, err
	}

	return &FileLogger{
		Enabled: *config.Enabled,
		logger:  log.New(config.Output, "", 0),
	}, nil
}

// shouldLog returns true if we can log.
func (l *FileLogger) shouldLog() bool {
	return l != nil && l.logger != nil &&
		// Check the log file is enabled
		l.Enabled
}

func (lfc *FileLoggerConfig) init(level LogLevel, logFilePath string, minAge int) error {
	if lfc == nil {
		return errors.New("nil LogFileConfig")
	}

	if lfc.Enabled == nil {
		// enable for all levels except debug by default
		lfc.Enabled = BoolPtr(level != LevelDebug)
	}

	if lfc.Rotation.MaxSize == nil {
		lfc.Rotation.MaxSize = &defaultMaxSize
	}

	if lfc.Rotation.MaxAge == nil {
		defaultMaxAge := minAge * defaultMaxAgeMultiplier
		lfc.Rotation.MaxAge = &defaultMaxAge
	} else if *lfc.Rotation.MaxAge == 0 {
		// A value of zero disables the age-based log cleanup in Lumberjack.
	} else if *lfc.Rotation.MaxAge < minAge {
		return fmt.Errorf("MaxAge for %s was set to %d which is below the minimum of %d", LogLevelName(level), *lfc.Rotation.MaxAge, minAge)
	} else if *lfc.Rotation.MaxAge > maxAgeLimit {
		return fmt.Errorf("MaxAge for %s was set to %d which is above the maximum of %d", LogLevelName(level), *lfc.Rotation.MaxAge, maxAgeLimit)
	}

	if lfc.Output == nil {
		lfc.Output = newLumberjackOutput(
			filepath.Join(filepath.FromSlash(logFilePath), "sg_"+LogLevelName(level)+".log"),
			*lfc.Rotation.MaxSize,
			*lfc.Rotation.MaxAge,
		)
	}

	return nil
}

func newLumberjackOutput(filename string, maxSize, maxAge int) *lumberjack.Logger {
	return &lumberjack.Logger{
		Filename: filename,
		MaxSize:  maxSize,
		MaxAge:   maxAge,
		Compress: true,
	}
}
<|endoftext|>


<commit_before>// nolint: vetshadow
package lite_test

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/tendermint/tendermint/lite"
)

func TestInquirerValidPath(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "inquiry-test"
	consHash := []byte("params")
	resHash := []byte("results")
	count := 50
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the keys by 1 each time
		keys = keys.Extend(1)
		vals := keys.ToValidators(vote, 0)
		h := int64(20 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// this should fail validation....
	commit := commits[count-1].Commit
	err := cert.Certify(commit)
	require.NotNil(err)

	// add a few seed in the middle should be insufficient
	for i := 10; i < 13; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.NotNil(err)

	// with more info, we succeed
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.Nil(err, "%+v", err)
}

func TestInquirerMinimalPath(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "minimal-path"
	consHash := []byte("other-params")
	count := 12
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the validators, so we are just below 2/3
		keys = keys.Extend(len(keys)/2 - 1)
		vals := keys.ToValidators(vote, 0)
		h := int64(5 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		resHash := []byte(fmt.Sprintf("res=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0, len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// this should fail validation....
	commit := commits[count-1].Commit
	err := cert.Certify(commit)
	require.NotNil(err)

	// add a few seed in the middle should be insufficient
	for i := 5; i < 8; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.NotNil(err)

	// with more info, we succeed
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.Nil(err, "%+v", err)
}

func TestInquirerVerifyHistorical(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "inquiry-test"
	count := 10
	consHash := []byte("special-params")
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the keys by 1 each time
		keys = keys.Extend(1)
		vals := keys.ToValidators(vote, 0)
		h := int64(20 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		resHash := []byte(fmt.Sprintf("res=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
			len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// store a few commits as trust
	for _, i := range []int{2, 5} {
		trust.StoreCommit(commits[i])
	}

	// let's see if we can jump forward using trusted commits
	err := source.StoreCommit(commits[7])
	require.Nil(err, "%+v", err)
	check := commits[7].Commit
	err = cert.Certify(check)
	require.Nil(err, "%+v", err)
	assert.Equal(check.Height(), cert.LastHeight())

	// add access to all commits via untrusted source
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}

	// try to check an unknown seed in the past
	mid := commits[3].Commit
	err = cert.Certify(mid)
	require.Nil(err, "%+v", err)
	assert.Equal(mid.Height(), cert.LastHeight())

	// and jump all the way forward again
	end := commits[count-1].Commit
	err = cert.Certify(end)
	require.Nil(err, "%+v", err)
	assert.Equal(end.Height(), cert.LastHeight())
}
<commit_msg>Fix formatting<commit_after>// nolint: vetshadow
package lite_test

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/tendermint/tendermint/lite"
)

func TestInquirerValidPath(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "inquiry-test"
	consHash := []byte("params")
	resHash := []byte("results")
	count := 50
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the keys by 1 each time
		keys = keys.Extend(1)
		vals := keys.ToValidators(vote, 0)
		h := int64(20 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
			len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// this should fail validation....
	commit := commits[count-1].Commit
	err := cert.Certify(commit)
	require.NotNil(err)

	// add a few seed in the middle should be insufficient
	for i := 10; i < 13; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.NotNil(err)

	// with more info, we succeed
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.Nil(err, "%+v", err)
}

func TestInquirerMinimalPath(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "minimal-path"
	consHash := []byte("other-params")
	count := 12
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the validators, so we are just below 2/3
		keys = keys.Extend(len(keys)/2 - 1)
		vals := keys.ToValidators(vote, 0)
		h := int64(5 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		resHash := []byte(fmt.Sprintf("res=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
			len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// this should fail validation....
	commit := commits[count-1].Commit
	err := cert.Certify(commit)
	require.NotNil(err)

	// add a few seed in the middle should be insufficient
	for i := 5; i < 8; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.NotNil(err)

	// with more info, we succeed
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}
	err = cert.Certify(commit)
	assert.Nil(err, "%+v", err)
}

func TestInquirerVerifyHistorical(t *testing.T) {
	assert, require := assert.New(t), require.New(t)
	trust := lite.NewMemStoreProvider()
	source := lite.NewMemStoreProvider()

	// set up the validators to generate test blocks
	var vote int64 = 10
	keys := lite.GenValKeys(5)

	// construct a bunch of commits, each with one more height than the last
	chainID := "inquiry-test"
	count := 10
	consHash := []byte("special-params")
	commits := make([]lite.FullCommit, count)
	for i := 0; i < count; i++ {
		// extend the keys by 1 each time
		keys = keys.Extend(1)
		vals := keys.ToValidators(vote, 0)
		h := int64(20 + 10*i)
		appHash := []byte(fmt.Sprintf("h=%d", h))
		resHash := []byte(fmt.Sprintf("res=%d", h))
		commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, resHash, 0,
			len(keys))
	}

	// initialize a certifier with the initial state
	cert, _ := lite.NewInquiring(chainID, commits[0], trust, source)

	// store a few commits as trust
	for _, i := range []int{2, 5} {
		trust.StoreCommit(commits[i])
	}

	// let's see if we can jump forward using trusted commits
	err := source.StoreCommit(commits[7])
	require.Nil(err, "%+v", err)
	check := commits[7].Commit
	err = cert.Certify(check)
	require.Nil(err, "%+v", err)
	assert.Equal(check.Height(), cert.LastHeight())

	// add access to all commits via untrusted source
	for i := 0; i < count; i++ {
		err := source.StoreCommit(commits[i])
		require.Nil(err)
	}

	// try to check an unknown seed in the past
	mid := commits[3].Commit
	err = cert.Certify(mid)
	require.Nil(err, "%+v", err)
	assert.Equal(mid.Height(), cert.LastHeight())

	// and jump all the way forward again
	end := commits[count-1].Commit
	err = cert.Certify(end)
	require.Nil(err, "%+v", err)
	assert.Equal(end.Height(), cert.LastHeight())
}
<|endoftext|>


<commit_before>package x509

/*
#cgo pkg-config: openssl
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>

#define d2i_X509_f 0
#define d2i_X509_REQ_f 1

static void *__d2i_X509_f_with_counter(unsigned int f, const unsigned char **in, long length, long *counter)
{
	const unsigned char *p = *in + *counter;
	void *c = NULL;

	switch (f) {
	case d2i_X509_f:
		c = d2i_X509(NULL, &p, length);
		break;
	case d2i_X509_REQ_f:
		c = d2i_X509_REQ(NULL, &p, length);
		break;
	default:
		break;
	}
	if (c == NULL)
		return NULL;
	*counter = p - *in;
	return c;
}

static X509 *d2i_X509_with_counter(const unsigned char **in, long length, long *counter)
{
	return (X509 *)__d2i_X509_f_with_counter(d2i_X509_f, in, length, counter);
}

static X509_REQ *d2i_X509_REQ_with_counter(const unsigned char **in, long length, long *counter)
{
	return (X509_REQ *)__d2i_X509_f_with_counter(d2i_X509_REQ_f, in, length, counter);
}

static int X509_get_version_no_macro(X509 *cert)
{
	return X509_get_version(cert);
}
*/
import "C"
import (
	"bytes"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
	"net"
	"unsafe"

	"github.com/shanemhansen/gossl/sslerr"
)

type PEMCipher int

// Possible values for the EncryptPEMBlock encryption algorithm.
const (
	_ PEMCipher = iota
	PEMCipherDES
	PEMCipher3DES
	PEMCipherAES128
	PEMCipherAES192
	PEMCipherAES256
)

// A Certificate represents an X.509 certificate.
type Certificate struct {
	x509 *C.X509
	Raw  []byte

	Version      int
	SerialNumber *big.Int
	Issuer       string
	Subject      string

	IPAddresses []net.IP
	DNSNames    []string

	//TODO(runcom): add more pub fields
}

func (c *Certificate) GetX509() *C.X509 {
	return c.x509
}

// ParseCertificate parses a single certificate from the given ASN.1 DER data.
func ParseCertificate(asn1Data []byte) (*Certificate, error) {
	var (
		c       *C.X509
		dlen    = C.long(len(asn1Data))
		buf     = (*C.uchar)(&asn1Data[0])
		counter = C.long(0)
	)
	c = C.d2i_X509_with_counter(&buf, dlen, &counter)
	if c == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	cert, err := getCertificate(asn1Data[:counter], c)
	if err != nil {
		return nil, err
	}
	return cert, nil
}

// ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding.
func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
	var (
		cs      []*Certificate
		dlen    = C.long(len(asn1Data))
		buf     = (*C.uchar)(&asn1Data[0])
		counter = C.long(0)
		prev    int
	)
	for counter < dlen {
		c := C.d2i_X509_with_counter(&buf, dlen, &counter)
		if c == nil {
			return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
		}
		cert, err := getCertificate(asn1Data[prev:counter], c)
		if err != nil {
			return nil, err
		}
		cs = append(cs, cert)
		prev = int(counter)
	}
	return cs, nil
}

func getCertificate(asn1Data []byte, x509 *C.X509) (*Certificate, error) {
	cert := &Certificate{}
	cert.x509 = x509
	// certificate raw data
	cert.Raw = asn1Data
	// certificate version (zero indexed)
	cert.Version = int(C.X509_get_version_no_macro(cert.x509)) + 1
	// certificate serial number
	cert.SerialNumber = big.NewInt(int64(C.ASN1_INTEGER_get(C.X509_get_serialNumber(cert.x509))))
	// TODO(runcom): store in pkix.Name
	// certificate subject
	cert.Subject = C.GoString(C.X509_NAME_oneline(C.X509_get_subject_name(cert.x509), nil, 0))
	// TODO(runcom): store in pkix.Name
	// certificate issuer
	cert.Issuer = C.GoString(C.X509_NAME_oneline(C.X509_get_issuer_name(cert.x509), nil, 0))
	return cert, nil
}

// CertificateRequest represents a PKCS #10, certificate signature request.
type CertificateRequest struct {
	req *C.X509_REQ

	//TODO(runcom): add more pub fields
}

// ParseCertificateRequest parses a single certificate request from the
// given ASN.1 DER data.
func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
	var (
		cr      *C.X509_REQ
		dlen    = C.long(len(asn1Data))
		buf     = (*C.uchar)(&asn1Data[0])
		counter = C.long(0)
	)
	cr = C.d2i_X509_REQ_with_counter(&buf, dlen, &counter)
	if cr == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	certReq, err := getCertificateRequest(asn1Data[:counter], cr)
	if err != nil {
		return nil, err
	}
	return certReq, nil
}

func getCertificateRequest(asn1Data []byte, req *C.X509_REQ) (*CertificateRequest, error) {
	cr := &CertificateRequest{}
	cr.req = req
	return cr, nil
}

// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
// CRL.
var pemCRLPrefix = []byte("-----BEGIN X509 CRL")

// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
// encoded CRLs will appear where they should be DER encoded, so this function
// will transparently handle PEM encoding as long as there isn't any leading
// garbage.
func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
	if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
		var (
			crl  *C.X509_CRL
			buf  = unsafe.Pointer(&crlBytes[0])
			blen = C.int(len(crlBytes))
			bio  = C.BIO_new_mem_buf(buf, blen)
		)
		crl = C.PEM_read_bio_X509_CRL(bio, nil, nil, nil)
		if crl != nil {
			// use crl
			return &pkix.CertificateList{}, nil
		}
	}
	return ParseDERCRL(crlBytes)
}

// ParseDERCRL parses a DER encoded CRL from the given bytes.
func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
	var (
		crl  *C.X509_CRL
		buf  = unsafe.Pointer(&derBytes[0])
		blen = C.int(len(derBytes))
		bio  = C.BIO_new_mem_buf(buf, blen)
	)
	crl = C.d2i_X509_CRL_bio(bio, nil)
	if crl == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	// use crl
	return &pkix.CertificateList{}, nil
}

func certificateListFromCRL(crl *C.X509_CRL) *pkix.CertificateList {
	return &pkix.CertificateList{}
}

// IncorrectPasswordError is returned when an incorrect password is detected.
var IncorrectPasswordError = errors.New("x509: decryption password incorrect")

// DecryptPEMBlock takes a password encrypted PEM block and the password used to
// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
// the DEK-Info header to determine the algorithm used for decryption. If no
// DEK-Info header is present, an error is returned. If an incorrect password
// is detected an IncorrectPasswordError is returned. Because of deficiencies
// in the encrypted-PEM format, it's not always possible to detect an incorrect
// password. In these cases no error will be returned but the decrypted DER
// bytes will be random noise.
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
	var (
		raw = b.Bytes
	)
	_ = raw

	return nil, nil
}

// EncryptPEMBlock returns a PEM block of the specified type holding the
// given DER-encoded data encrypted with the specified algorithm and
// password.
func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
	return nil, nil
}

// IsEncryptedPEMBlock returns if the PEM block is password encrypted.
func IsEncryptedPEMBlock(b *pem.Block) bool {
	return x509.IsEncryptedPEMBlock(b)
}

// taken from old, top ns, gossl

//Export an OpenSSL X509 to a DER buffer
func (self *Certificate) DumpDERCertificate() ([]byte, error) {
	bio := C.BIO_new(C.BIO_s_mem())
	defer C.BIO_free(bio)
	ret := C.i2d_X509_bio(bio, self.x509)
	if ret == 0 {
		return nil, errors.New("problem dumping certificate")
	}
	var temp *C.char
	buf_len := C.BIO_ctrl(bio, C.BIO_CTRL_INFO, 0, unsafe.Pointer(&temp))
	return C.GoBytes(unsafe.Pointer(temp), C.int(buf_len)), nil
}

//Helper function that calls encoding/pem to convert DER to PEM
func ParseCertificatePEM(pemData []byte) (*Certificate, error) {
	length := C.int(len(pemData))
	buffer := unsafe.Pointer(&pemData[0])
	bio := C.BIO_new_mem_buf(buffer, length)
	cert := C.PEM_read_bio_X509(bio, nil, nil, nil)
	if cert == nil {
		return nil, errors.New("problem loading certificate" + sslerr.SSLErrorMessage().String())
	}
	return &Certificate{x509: cert}, nil

}

type X509Store struct {
	Store *C.X509_STORE
}

func NewX509Store(ctx unsafe.Pointer) *X509Store {
	cctx := (*C.SSL_CTX)(ctx)
	return &X509Store{Store: C.SSL_CTX_get_cert_store(cctx)}
}

func (self *X509Store) SetDepth(depth int) int {
	return int(C.X509_STORE_set_depth(self.Store, C.int(depth)))
}
func (self *X509Store) AddCert(cert *Certificate) int {
	return int(C.X509_STORE_add_cert(self.Store, cert.x509))
}

type X509Name struct {
	Name *C.X509_NAME
}

func (self *X509Name) Print() ([]byte, error) {
	bio := C.BIO_new(C.BIO_s_mem())
	defer C.BIO_free(bio)
	//TODO check for error here
	C.X509_NAME_print_ex(bio, self.Name, 0, C.XN_FLAG_MULTILINE)
	var temp *C.char
	buf_len := C.BIO_ctrl(bio, C.BIO_CTRL_INFO, 0, unsafe.Pointer(&temp))
	defer C.free(unsafe.Pointer(temp))
	return C.GoBytes(unsafe.Pointer(temp), C.int(buf_len)), nil
}
<commit_msg>crypto/x509: fix go pointer to cgo<commit_after>package x509

/*
#cgo pkg-config: openssl
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>

#define d2i_X509_f 0
#define d2i_X509_REQ_f 1

static void *__d2i_X509_f_with_counter(unsigned int f, const unsigned char **in, long length, long *counter)
{
	const unsigned char *p = *in + *counter;
	void *c = NULL;

	switch (f) {
	case d2i_X509_f:
		c = d2i_X509(NULL, &p, length);
		break;
	case d2i_X509_REQ_f:
		c = d2i_X509_REQ(NULL, &p, length);
		break;
	default:
		break;
	}
	if (c == NULL)
		return NULL;
	*counter = p - *in;
	return c;
}

static X509 *d2i_X509_with_counter(const unsigned char **in, long length, long *counter)
{
	return (X509 *)__d2i_X509_f_with_counter(d2i_X509_f, in, length, counter);
}

static X509_REQ *d2i_X509_REQ_with_counter(const unsigned char **in, long length, long *counter)
{
	return (X509_REQ *)__d2i_X509_f_with_counter(d2i_X509_REQ_f, in, length, counter);
}

static int X509_get_version_no_macro(X509 *cert)
{
	return X509_get_version(cert);
}
*/
import "C"
import (
	"bytes"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
	"net"
	"unsafe"

	"github.com/shanemhansen/gossl/sslerr"
)

type PEMCipher int

// Possible values for the EncryptPEMBlock encryption algorithm.
const (
	_ PEMCipher = iota
	PEMCipherDES
	PEMCipher3DES
	PEMCipherAES128
	PEMCipherAES192
	PEMCipherAES256
)

// A Certificate represents an X.509 certificate.
type Certificate struct {
	x509 *C.X509
	Raw  []byte

	Version      int
	SerialNumber *big.Int
	Issuer       string
	Subject      string

	IPAddresses []net.IP
	DNSNames    []string

	//TODO(runcom): add more pub fields
}

func (c *Certificate) GetX509() *C.X509 {
	return c.x509
}

// ParseCertificate parses a single certificate from the given ASN.1 DER data.
func ParseCertificate(asn1Data []byte) (*Certificate, error) {
	var (
		c       *C.X509
		dlen    = C.long(len(asn1Data))
		p       = C.malloc(C.size_t(len(asn1Data)))
		counter = C.long(0)
	)
	defer C.free(p)
	cBuf := (*[1 << 30]byte)(p)
	copy(cBuf[:], asn1Data)
	c = C.d2i_X509_with_counter((**C.uchar)(unsafe.Pointer(&cBuf)), dlen, &counter)
	if c == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	cert, err := getCertificate(asn1Data[:counter], c)
	if err != nil {
		return nil, err
	}
	return cert, nil
}

// ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding.
func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
	var (
		cs      []*Certificate
		dlen    = C.long(len(asn1Data))
		p       = C.malloc(C.size_t(len(asn1Data)))
		counter = C.long(0)
		prev    int
	)
	defer C.free(p)
	cBuf := (*[1 << 30]byte)(p)
	copy(cBuf[:], asn1Data)
	for counter < dlen {
		c := C.d2i_X509_with_counter((**C.uchar)(unsafe.Pointer(&cBuf)), dlen, &counter)
		if c == nil {
			return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
		}
		cert, err := getCertificate(asn1Data[prev:counter], c)
		if err != nil {
			return nil, err
		}
		cs = append(cs, cert)
		prev = int(counter)
	}
	return cs, nil
}

func getCertificate(asn1Data []byte, x509 *C.X509) (*Certificate, error) {
	cert := &Certificate{}
	cert.x509 = x509
	// certificate raw data
	cert.Raw = asn1Data
	// certificate version (zero indexed)
	cert.Version = int(C.X509_get_version_no_macro(cert.x509)) + 1
	// certificate serial number
	cert.SerialNumber = big.NewInt(int64(C.ASN1_INTEGER_get(C.X509_get_serialNumber(cert.x509))))
	// TODO(runcom): store in pkix.Name
	// certificate subject
	cert.Subject = C.GoString(C.X509_NAME_oneline(C.X509_get_subject_name(cert.x509), nil, 0))
	// TODO(runcom): store in pkix.Name
	// certificate issuer
	cert.Issuer = C.GoString(C.X509_NAME_oneline(C.X509_get_issuer_name(cert.x509), nil, 0))
	return cert, nil
}

// CertificateRequest represents a PKCS #10, certificate signature request.
type CertificateRequest struct {
	req *C.X509_REQ

	//TODO(runcom): add more pub fields
}

// ParseCertificateRequest parses a single certificate request from the
// given ASN.1 DER data.
func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
	var (
		cr      *C.X509_REQ
		dlen    = C.long(len(asn1Data))
		buf     = (*C.uchar)(&asn1Data[0])
		counter = C.long(0)
	)
	cr = C.d2i_X509_REQ_with_counter(&buf, dlen, &counter)
	if cr == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	certReq, err := getCertificateRequest(asn1Data[:counter], cr)
	if err != nil {
		return nil, err
	}
	return certReq, nil
}

func getCertificateRequest(asn1Data []byte, req *C.X509_REQ) (*CertificateRequest, error) {
	cr := &CertificateRequest{}
	cr.req = req
	return cr, nil
}

// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
// CRL.
var pemCRLPrefix = []byte("-----BEGIN X509 CRL")

// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
// encoded CRLs will appear where they should be DER encoded, so this function
// will transparently handle PEM encoding as long as there isn't any leading
// garbage.
func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
	if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
		var (
			crl  *C.X509_CRL
			buf  = unsafe.Pointer(&crlBytes[0])
			blen = C.int(len(crlBytes))
			bio  = C.BIO_new_mem_buf(buf, blen)
		)
		crl = C.PEM_read_bio_X509_CRL(bio, nil, nil, nil)
		if crl != nil {
			// use crl
			return &pkix.CertificateList{}, nil
		}
	}
	return ParseDERCRL(crlBytes)
}

// ParseDERCRL parses a DER encoded CRL from the given bytes.
func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
	var (
		crl  *C.X509_CRL
		buf  = unsafe.Pointer(&derBytes[0])
		blen = C.int(len(derBytes))
		bio  = C.BIO_new_mem_buf(buf, blen)
	)
	crl = C.d2i_X509_CRL_bio(bio, nil)
	if crl == nil {
		return nil, errors.New("error parsing der data: " + sslerr.SSLErrorMessage().String())
	}
	// use crl
	return &pkix.CertificateList{}, nil
}

func certificateListFromCRL(crl *C.X509_CRL) *pkix.CertificateList {
	return &pkix.CertificateList{}
}

// IncorrectPasswordError is returned when an incorrect password is detected.
var IncorrectPasswordError = errors.New("x509: decryption password incorrect")

// DecryptPEMBlock takes a password encrypted PEM block and the password used to
// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
// the DEK-Info header to determine the algorithm used for decryption. If no
// DEK-Info header is present, an error is returned. If an incorrect password
// is detected an IncorrectPasswordError is returned. Because of deficiencies
// in the encrypted-PEM format, it's not always possible to detect an incorrect
// password. In these cases no error will be returned but the decrypted DER
// bytes will be random noise.
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
	var (
		raw = b.Bytes
	)
	_ = raw

	return nil, nil
}

// EncryptPEMBlock returns a PEM block of the specified type holding the
// given DER-encoded data encrypted with the specified algorithm and
// password.
func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
	return nil, nil
}

// IsEncryptedPEMBlock returns if the PEM block is password encrypted.
func IsEncryptedPEMBlock(b *pem.Block) bool {
	return x509.IsEncryptedPEMBlock(b)
}

// taken from old, top ns, gossl

//Export an OpenSSL X509 to a DER buffer
func (self *Certificate) DumpDERCertificate() ([]byte, error) {
	bio := C.BIO_new(C.BIO_s_mem())
	defer C.BIO_free(bio)
	ret := C.i2d_X509_bio(bio, self.x509)
	if ret == 0 {
		return nil, errors.New("problem dumping certificate")
	}
	var temp *C.char
	buf_len := C.BIO_ctrl(bio, C.BIO_CTRL_INFO, 0, unsafe.Pointer(&temp))
	return C.GoBytes(unsafe.Pointer(temp), C.int(buf_len)), nil
}

//Helper function that calls encoding/pem to convert DER to PEM
func ParseCertificatePEM(pemData []byte) (*Certificate, error) {
	length := C.int(len(pemData))
	buffer := unsafe.Pointer(&pemData[0])
	bio := C.BIO_new_mem_buf(buffer, length)
	cert := C.PEM_read_bio_X509(bio, nil, nil, nil)
	if cert == nil {
		return nil, errors.New("problem loading certificate" + sslerr.SSLErrorMessage().String())
	}
	return &Certificate{x509: cert}, nil

}

type X509Store struct {
	Store *C.X509_STORE
}

func NewX509Store(ctx unsafe.Pointer) *X509Store {
	cctx := (*C.SSL_CTX)(ctx)
	return &X509Store{Store: C.SSL_CTX_get_cert_store(cctx)}
}

func (self *X509Store) SetDepth(depth int) int {
	return int(C.X509_STORE_set_depth(self.Store, C.int(depth)))
}
func (self *X509Store) AddCert(cert *Certificate) int {
	return int(C.X509_STORE_add_cert(self.Store, cert.x509))
}

type X509Name struct {
	Name *C.X509_NAME
}

func (self *X509Name) Print() ([]byte, error) {
	bio := C.BIO_new(C.BIO_s_mem())
	defer C.BIO_free(bio)
	//TODO check for error here
	C.X509_NAME_print_ex(bio, self.Name, 0, C.XN_FLAG_MULTILINE)
	var temp *C.char
	buf_len := C.BIO_ctrl(bio, C.BIO_CTRL_INFO, 0, unsafe.Pointer(&temp))
	defer C.free(unsafe.Pointer(temp))
	return C.GoBytes(unsafe.Pointer(temp), C.int(buf_len)), nil
}
<|endoftext|>


<commit_before>package models

import (
    "errors"
    "github.com/orc/db"
    // "github.com/orc/mailer"
    "github.com/orc/utils"
    "strconv"
)

type PersonsModel struct {
    Entity
}

type Person struct {
    Id      int    `name:"id" type:"int" null:"NOT NULL" extra:"PRIMARY"`
    FaceId  int    `name:"face_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"faces" refField:"id" refFieldShow:"id"`
    GroupId int    `name:"group_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"groups" refField:"id" refFieldShow:"name"`
    Token   string `name:"token" type:"text" null:"NOT NULL" extra:""`
    Status  bool   `name:"status" type:"boolean" null:"NOT NULL" extra:""`
}

func (c *ModelManager) Persons() *PersonsModel {
    model := new(PersonsModel)

    model.TableName = "persons"
    model.Caption = "Участники"

    model.Columns = []string{"id", "face_id", "group_id", "status"}
    model.ColNames = []string{"ID", "Физическое лицо", "Группа", "Статус"}

    model.Fields = new(Person)
    model.WherePart = make(map[string]interface{}, 0)
    model.Condition = AND
    model.OrderBy = "id"
    model.Limit = "ALL"
    model.Offset = 0

    model.Sub = false
    model.SubTable = nil
    model.SubField = ""

    return model
}

const HASH_SIZE = 32

func (this *PersonsModel) Add(userId int, params map[string]interface{}) error {
    // var to string
    // var address string

    token := utils.GetRandSeq(HASH_SIZE)
    params["token"] = token

    query := `SELECT param_values.value
        FROM reg_param_vals
        INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
        INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
        INNER JOIN params ON params.id = param_values.param_id
        INNER JOIN events ON events.id = registrations.event_id
        INNER JOIN faces ON faces.id = registrations.face_id
        INNER JOIN users ON users.id = faces.user_id
        WHERE params.id in (5, 6, 7) AND users.id = $1 AND events.id = 1 ORDER BY params.id;`
    data := db.Query(query, []interface{}{userId})
    headName := ""
    if len(data) < 3 {
        return errors.New("Данные о руководителе группы отсутсвуют.")

    } else {
        headName = data[0].(map[string]interface{})["value"].(string)
        headName += " " + data[1].(map[string]interface{})["value"].(string)
        headName += " " + data[2].(map[string]interface{})["value"].(string)
    }

    groupId, err := strconv.Atoi(params["group_id"].(string))
    if err != nil {
        return err
    }

    var groupName string
    db.QueryRow("SELECT name FROM groups WHERE id = $1;", []interface{}{groupId}).Scan(&groupName)

    // query = `SELECT param_values.value
    //     FROM reg_param_vals
    //     INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
    //     INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
    //     INNER JOIN params ON params.id = param_values.param_id
    //     INNER JOIN events ON events.id = registrations.event_id
    //     INNER JOIN faces ON faces.id = registrations.face_id
    //     INNER JOIN users ON users.id = faces.user_id
    //     WHERE params.id in (4, 5, 6, 7) AND faces.id = $1 AND events.id = 1 ORDER BY params.id;`
    // data = db.Query(query, []interface{}{params["face_id"]})
    // if len(data) < 4 {
    //     return errors.New("Данные о приглашаемом участнике отсутсвуют.")

    // } else {
    //     address = data[0].(map[string]interface{})["value"].(string)
    //     to = data[1].(map[string]interface{})["value"].(string)
    //     to += " " + data[2].(map[string]interface{})["value"].(string)
    //     to += " " + data[3].(map[string]interface{})["value"].(string)
    // }

    // if !mailer.InviteToGroup(to, address, token, headName, groupName) {
    //     return errors.New("Участник скорее всего указал неправильный email, отправить письмо-приглашенине невозможно")
    // }

    this.LoadModelData(params)
    db.QueryInsert_(this, "").Scan()
    return nil
}

func (this *PersonsModel) Select(fields []string, filters map[string]interface{}, limit, offset int, sord, sidx string) (result []interface{}) {
    if len(fields) == 0 {
        return nil
    }

    query := `SELECT `

    for _, field := range fields {
        switch field {
        case "id":
            query += "persons.id, "
            break
        case "group_id":
            query += "groups.name as group_name, "
            break
        case "status":
            query += "persons.status, "
            break
        case "face_id":
            query += "array_to_string(array_agg(param_values.value), ' ') as face_name, "
            break
        }
    }

    query = query[:len(query)-2]

    query += ` FROM reg_param_vals
        INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
        INNER JOIN faces ON faces.id = registrations.face_id
        INNER JOIN events ON events.id = registrations.event_id
        INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
        INNER JOIN params ON params.id = param_values.param_id
        INNER JOIN persons ON persons.face_id = faces.id
        INNER JOIN groups ON groups.face_id = groups.id`

    where, params, _ := this.Where(filters, 1)

    if where != "" {
        query += ` WHERE ` + where + ` AND params.id in (5, 6, 7) AND events.id = 1 GROUP BY persons.id, groups.id`
    } else {
        query += ` WHERE params.id in (5, 6, 7) AND events.id = 1 GROUP BY persons.id, groups.id`
    }

    if sidx != "" {
        query += ` ORDER BY persons.`+sidx
    }

    query += ` `+ sord

    if limit != -1 {
        params = append(params, limit)
        query += ` LIMIT $`+strconv.Itoa(len(params))
    }

    if offset != -1 {
        params = append(params, offset)
        query += ` OFFSET $`+strconv.Itoa(len(params))
    }

    query += `;`

    return db.Query(query, params)
}

func (this *PersonsModel) GetColModel(isAdmin bool, userId int) []map[string]interface{} {
    var query, groups, faces string

    if isAdmin {
        query = `SELECT array_to_string(
            array(SELECT groups.id || ':' || groups.name
            FROM groups
            GROUP BY groups.id ORDER BY groups), ';') as name;`
        groups = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)

        query = `SELECT array_to_string(
            array(SELECT faces.id || ':' || array_to_string(array_agg(param_values.value), ' ')
            FROM reg_param_vals
            INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
            INNER JOIN faces ON faces.id = registrations.face_id
            INNER JOIN events ON events.id = registrations.event_id
            INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
            INNER JOIN params ON params.id = param_values.param_id
            WHERE params.id in (5, 6, 7) AND events.id = 1 GROUP BY faces.id ORDER BY faces.id), ';') as name;`
        faces = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)
    } else {
        query = `SELECT array_to_string(
            array(SELECT groups.id || ':' || groups.name FROM groups
            INNER JOIN faces ON faces.id = groups.face_id
            INNER JOIN users ON users.id = faces.user_id
            WHERE users.id = $1 AND groups.id NOT IN (SELECT group_registrations.group_id FROM group_registrations)
            GROUP BY groups.id ORDER BY groups), ';') as name;`
        groups = db.Query(query, []interface{}{userId})[0].(map[string]interface{})["name"].(string)

        query = `SELECT array_to_string(
            array(SELECT faces.id || ':' || array_to_string(array_agg(param_values.value), ' ')
            FROM reg_param_vals
            INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
            INNER JOIN faces ON faces.id = registrations.face_id
            INNER JOIN events ON events.id = registrations.event_id
            INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
            INNER JOIN params ON params.id = param_values.param_id
            WHERE params.id in (5, 6, 7) GROUP BY faces.id ORDER BY faces.id), ';') as name;`
        faces = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)
    }

    return []map[string]interface{} {
        0: map[string]interface{} {
            "index": "id",
            "name": "id",
            "editable": false,
        },
        1: map[string]interface{} {
            "index": "face_id",
            "name": "face_id",
            "editable": true,
            "formatter": "select",
            "edittype": "select",
            "stype": "select",
            "search": true,
            "editrules": map[string]interface{}{"required": true},
            "editoptions": map[string]string{"value": faces},
            "searchoptions": map[string]string{"value": ":Все;"+faces},
        },
        2: map[string]interface{} {
            "index": "group_id",
            "name": "group_id",
            "editable": true,
            "formatter": "select",
            "edittype": "select",
            "stype": "select",
            "search": true,
            "editrules": map[string]interface{}{"required": true},
            "editoptions": map[string]string{"value": groups},
            "searchoptions": map[string]string{"value": ":Все;"+groups},
        },
        3: map[string]interface{} {
            "index": "status",
            "name": "status",
            "editable": true,
            "editrules": map[string]interface{}{"required": true},
            "formatter": "checkbox",
            "formatoptions": map[string]interface{}{"disabled": true},
            "edittype": "checkbox",
            "editoptions": map[string]interface{}{"value": "true:false"},
        },
    }
}
<commit_msg>persons::GetColModel: add comdition `events.id = 1`<commit_after>package models

import (
    "errors"
    "github.com/orc/db"
    // "github.com/orc/mailer"
    "github.com/orc/utils"
    "strconv"
)

type PersonsModel struct {
    Entity
}

type Person struct {
    Id      int    `name:"id" type:"int" null:"NOT NULL" extra:"PRIMARY"`
    FaceId  int    `name:"face_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"faces" refField:"id" refFieldShow:"id"`
    GroupId int    `name:"group_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"groups" refField:"id" refFieldShow:"name"`
    Token   string `name:"token" type:"text" null:"NOT NULL" extra:""`
    Status  bool   `name:"status" type:"boolean" null:"NOT NULL" extra:""`
}

func (c *ModelManager) Persons() *PersonsModel {
    model := new(PersonsModel)

    model.TableName = "persons"
    model.Caption = "Участники"

    model.Columns = []string{"id", "face_id", "group_id", "status"}
    model.ColNames = []string{"ID", "Физическое лицо", "Группа", "Статус"}

    model.Fields = new(Person)
    model.WherePart = make(map[string]interface{}, 0)
    model.Condition = AND
    model.OrderBy = "id"
    model.Limit = "ALL"
    model.Offset = 0

    model.Sub = false
    model.SubTable = nil
    model.SubField = ""

    return model
}

const HASH_SIZE = 32

func (this *PersonsModel) Add(userId int, params map[string]interface{}) error {
    // var to string
    // var address string

    token := utils.GetRandSeq(HASH_SIZE)
    params["token"] = token

    query := `SELECT param_values.value
        FROM reg_param_vals
        INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
        INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
        INNER JOIN params ON params.id = param_values.param_id
        INNER JOIN events ON events.id = registrations.event_id
        INNER JOIN faces ON faces.id = registrations.face_id
        INNER JOIN users ON users.id = faces.user_id
        WHERE params.id in (5, 6, 7) AND users.id = $1 AND events.id = 1 ORDER BY params.id;`
    data := db.Query(query, []interface{}{userId})
    headName := ""
    if len(data) < 3 {
        return errors.New("Данные о руководителе группы отсутсвуют.")

    } else {
        headName = data[0].(map[string]interface{})["value"].(string)
        headName += " " + data[1].(map[string]interface{})["value"].(string)
        headName += " " + data[2].(map[string]interface{})["value"].(string)
    }

    groupId, err := strconv.Atoi(params["group_id"].(string))
    if err != nil {
        return err
    }

    var groupName string
    db.QueryRow("SELECT name FROM groups WHERE id = $1;", []interface{}{groupId}).Scan(&groupName)

    // query = `SELECT param_values.value
    //     FROM reg_param_vals
    //     INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
    //     INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
    //     INNER JOIN params ON params.id = param_values.param_id
    //     INNER JOIN events ON events.id = registrations.event_id
    //     INNER JOIN faces ON faces.id = registrations.face_id
    //     INNER JOIN users ON users.id = faces.user_id
    //     WHERE params.id in (4, 5, 6, 7) AND faces.id = $1 AND events.id = 1 ORDER BY params.id;`
    // data = db.Query(query, []interface{}{params["face_id"]})
    // if len(data) < 4 {
    //     return errors.New("Данные о приглашаемом участнике отсутсвуют.")

    // } else {
    //     address = data[0].(map[string]interface{})["value"].(string)
    //     to = data[1].(map[string]interface{})["value"].(string)
    //     to += " " + data[2].(map[string]interface{})["value"].(string)
    //     to += " " + data[3].(map[string]interface{})["value"].(string)
    // }

    // if !mailer.InviteToGroup(to, address, token, headName, groupName) {
    //     return errors.New("Участник скорее всего указал неправильный email, отправить письмо-приглашенине невозможно")
    // }

    this.LoadModelData(params)
    db.QueryInsert_(this, "").Scan()
    return nil
}

func (this *PersonsModel) Select(fields []string, filters map[string]interface{}, limit, offset int, sord, sidx string) (result []interface{}) {
    if len(fields) == 0 {
        return nil
    }

    query := `SELECT `

    for _, field := range fields {
        switch field {
        case "id":
            query += "persons.id, "
            break
        case "group_id":
            query += "groups.name as group_name, "
            break
        case "status":
            query += "persons.status, "
            break
        case "face_id":
            query += "array_to_string(array_agg(param_values.value), ' ') as face_name, "
            break
        }
    }

    query = query[:len(query)-2]

    query += ` FROM reg_param_vals
        INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
        INNER JOIN faces ON faces.id = registrations.face_id
        INNER JOIN events ON events.id = registrations.event_id
        INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
        INNER JOIN params ON params.id = param_values.param_id
        INNER JOIN persons ON persons.face_id = faces.id
        INNER JOIN groups ON groups.face_id = groups.id`

    where, params, _ := this.Where(filters, 1)

    if where != "" {
        query += ` WHERE ` + where + ` AND params.id in (5, 6, 7) AND events.id = 1 GROUP BY persons.id, groups.id`
    } else {
        query += ` WHERE params.id in (5, 6, 7) AND events.id = 1 GROUP BY persons.id, groups.id`
    }

    if sidx != "" {
        query += ` ORDER BY persons.`+sidx
    }

    query += ` `+ sord

    if limit != -1 {
        params = append(params, limit)
        query += ` LIMIT $`+strconv.Itoa(len(params))
    }

    if offset != -1 {
        params = append(params, offset)
        query += ` OFFSET $`+strconv.Itoa(len(params))
    }

    query += `;`

    return db.Query(query, params)
}

func (this *PersonsModel) GetColModel(isAdmin bool, userId int) []map[string]interface{} {
    var query, groups, faces string

    if isAdmin {
        query = `SELECT array_to_string(
            array(SELECT groups.id || ':' || groups.name
            FROM groups
            GROUP BY groups.id ORDER BY groups), ';') as name;`
        groups = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)

        query = `SELECT array_to_string(
            array(SELECT faces.id || ':' || array_to_string(array_agg(param_values.value), ' ')
            FROM reg_param_vals
            INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
            INNER JOIN faces ON faces.id = registrations.face_id
            INNER JOIN events ON events.id = registrations.event_id
            INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
            INNER JOIN params ON params.id = param_values.param_id
            WHERE params.id in (5, 6, 7) AND events.id = 1 GROUP BY faces.id ORDER BY faces.id), ';') as name;`
        faces = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)
    } else {
        query = `SELECT array_to_string(
            array(SELECT groups.id || ':' || groups.name FROM groups
            INNER JOIN faces ON faces.id = groups.face_id
            INNER JOIN users ON users.id = faces.user_id
            WHERE users.id = $1 AND groups.id NOT IN (SELECT group_registrations.group_id FROM group_registrations)
            GROUP BY groups.id ORDER BY groups), ';') as name;`
        groups = db.Query(query, []interface{}{userId})[0].(map[string]interface{})["name"].(string)

        query = `SELECT array_to_string(
            array(SELECT faces.id || ':' || array_to_string(array_agg(param_values.value), ' ')
            FROM reg_param_vals
            INNER JOIN registrations ON registrations.id = reg_param_vals.reg_id
            INNER JOIN faces ON faces.id = registrations.face_id
            INNER JOIN events ON events.id = registrations.event_id
            INNER JOIN param_values ON param_values.id = reg_param_vals.param_val_id
            INNER JOIN params ON params.id = param_values.param_id
            WHERE params.id in (5, 6, 7) AND events.id = 1 GROUP BY faces.id ORDER BY faces.id), ';') as name;`
        faces = db.Query(query, nil)[0].(map[string]interface{})["name"].(string)
    }

    return []map[string]interface{} {
        0: map[string]interface{} {
            "index": "id",
            "name": "id",
            "editable": false,
        },
        1: map[string]interface{} {
            "index": "face_id",
            "name": "face_id",
            "editable": true,
            "formatter": "select",
            "edittype": "select",
            "stype": "select",
            "search": true,
            "editrules": map[string]interface{}{"required": true},
            "editoptions": map[string]string{"value": faces},
            "searchoptions": map[string]string{"value": ":Все;"+faces},
        },
        2: map[string]interface{} {
            "index": "group_id",
            "name": "group_id",
            "editable": true,
            "formatter": "select",
            "edittype": "select",
            "stype": "select",
            "search": true,
            "editrules": map[string]interface{}{"required": true},
            "editoptions": map[string]string{"value": groups},
            "searchoptions": map[string]string{"value": ":Все;"+groups},
        },
        3: map[string]interface{} {
            "index": "status",
            "name": "status",
            "editable": true,
            "editrules": map[string]interface{}{"required": true},
            "formatter": "checkbox",
            "formatoptions": map[string]interface{}{"disabled": true},
            "edittype": "checkbox",
            "editoptions": map[string]interface{}{"value": "true:false"},
        },
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 logrus

import (
	"io"

	lg "github.com/Sirupsen/logrus"
	"github.com/ligato/cn-infra/logging"
)

var (
	// logf is the default logger used by package global functions.
	logf  *Logger
	depth int
	// ErrorKey is the key used to log an error object in structured form. See WithFields function.
	ErrorKey string
)

// Fields is a type for structured log entries.
type Fields map[string]interface{}

const locKey = "loc"
const tagKey = "tag"

const defaultLoggerName = "defaultLogger"

func init() {
	LoggerRegistry = &LogRegistry{mapping: map[string]*Logger{}}
	logf, _ = NewNamed(defaultLoggerName)
	depth = 2
	ErrorKey = lg.ErrorKey
}

// StandardLogger default logger instance used by package level functions.
func StandardLogger() *Logger {
	return logf
}

// InitTag sets the tag for the main go routine in the standard logger.
func InitTag(tag ...string) {
	logf.InitTag(tag...)
}

// GetTag returns the tag set for the current go routine in the standard logger.
func GetTag() string {
	return logf.GetTag()
}

// SetTag sets a tag in the standard logger.
func SetTag(tag ...string) {
	logf.SetTag(tag...)
}

// ClearTag remove a previously set tag in the standard logger.
func ClearTag() {
	logf.ClearTag()
}

// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
	logf.SetOutput(out)
}

// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter lg.Formatter) {
	logf.SetFormatter(formatter)
}

// SetLevel sets the standard logger level.
func SetLevel(level logging.LogLevel) {
	logf.SetLevel(level)
}

// GetLevel returns the standard logger level.
func GetLevel() logging.LogLevel {
	return logf.GetLevel()
}

// AddHook adds a hook to the standard logger hooks.
func AddHook(hook lg.Hook) {
	logf.AddHook(hook)
}

// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
func WithError(err error) *Entry {
	entry := logf.withField(ErrorKey, err, 1)
	return entry
}

// WithField creates an entry from the standard logger and adds a field to
// it. If you want multiple fields, use `WithFields`.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithField(key string, value interface{}) logging.LogWithLevel {
	entry := logf.withField(key, value, 1)
	return entry
}

// WithFields creates an entry from the standard logger and adds multiple
// fields to it. This is simply a helper for `WithField`, invoking it
// once for each field.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
//func WithFields(fields lg.Fields) *Entry {
func WithFields(fields Fields) *Entry {
	entry := logf.withFields(fields, 1)
	return entry
}

func header(d int) *Entry {
	t := logf.GetTag()
	l := logf.GetLineInfo(depth + d)
	e := WithFields(Fields{
		tagKey: t,
		locKey: l,
	})
	return e
}

// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
	header(1).Debug(args...)
}

// Print logs a message at level Info on the standard logger.
func Print(args ...interface{}) {
	header(1).Print(args...)
}

// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
	header(1).Info(args...)
}

// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
	header(1).Warn(args...)
}

// Warning logs a message at level Warn on the standard logger.
func Warning(args ...interface{}) {
	header(1).Warning(args...)
}

// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
	header(1).Error(args...)
}

// Panic logs a message at level Panic on the standard logger.
func Panic(args ...interface{}) {
	header(1).Panic(args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
	header(1).Fatal(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
	header(1).Debugf(format, args...)
}

// Printf logs a message at level Info on the standard logger.
func Printf(format string, args ...interface{}) {
	header(1).Printf(format, args...)
}

// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
	header(1).Infof(format, args...)
}

// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
	header(1).Warnf(format, args...)
}

// Warningf logs a message at level Warn on the standard logger.
func Warningf(format string, args ...interface{}) {
	header(1).Warningf(format, args...)
}

// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
	header(1).Errorf(format, args...)
}

// Panicf logs a message at level Panic on the standard logger.
func Panicf(format string, args ...interface{}) {
	header(1).Panicf(format, args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
	header(1).Fatalf(format, args...)
}

// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
	header(1).Debugln(args...)
}

// Println logs a message at level Info on the standard logger.
func Println(args ...interface{}) {
	header(1).Println(args...)
}

// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
	header(1).Infoln(args...)
}

// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
	header(1).Warnln(args...)
}

// Warningln logs a message at level Warn on the standard logger.
func Warningln(args ...interface{}) {
	header(1).Warningln(args...)
}

// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
	header(1).Errorln(args...)
}

// Panicln logs a message at level Panic on the standard logger.
func Panicln(args ...interface{}) {
	header(1).Panicln(args...)
}

// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
	header(1).Fatalln(args...)
}
<commit_msg>Use generic type<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 logrus

import (
	"io"

	lg "github.com/Sirupsen/logrus"
	"github.com/ligato/cn-infra/logging"
)

var (
	// logf is the default logger used by package global functions.
	logf  *Logger
	depth int
	// ErrorKey is the key used to log an error object in structured form. See WithFields function.
	ErrorKey string
)

// Fields is a type for structured log entries.
type Fields map[string]interface{}

const locKey = "loc"
const tagKey = "tag"

const defaultLoggerName = "defaultLogger"

func init() {
	LoggerRegistry = &LogRegistry{mapping: map[string]*Logger{}}
	logf, _ = NewNamed(defaultLoggerName)
	depth = 2
	ErrorKey = lg.ErrorKey
}

// StandardLogger default logger instance used by package level functions.
func StandardLogger() *Logger {
	return logf
}

// InitTag sets the tag for the main go routine in the standard logger.
func InitTag(tag ...string) {
	logf.InitTag(tag...)
}

// GetTag returns the tag set for the current go routine in the standard logger.
func GetTag() string {
	return logf.GetTag()
}

// SetTag sets a tag in the standard logger.
func SetTag(tag ...string) {
	logf.SetTag(tag...)
}

// ClearTag remove a previously set tag in the standard logger.
func ClearTag() {
	logf.ClearTag()
}

// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
	logf.SetOutput(out)
}

// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter lg.Formatter) {
	logf.SetFormatter(formatter)
}

// SetLevel sets the standard logger level.
func SetLevel(level logging.LogLevel) {
	logf.SetLevel(level)
}

// GetLevel returns the standard logger level.
func GetLevel() logging.LogLevel {
	return logf.GetLevel()
}

// AddHook adds a hook to the standard logger hooks.
func AddHook(hook lg.Hook) {
	logf.AddHook(hook)
}

// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
func WithError(err error) *Entry {
	entry := logf.withField(ErrorKey, err, 1)
	return entry
}

// WithField creates an entry from the standard logger and adds a field to
// it. If you want multiple fields, use `WithFields`.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithField(key string, value interface{}) logging.LogWithLevel {
	entry := logf.withField(key, value, 1)
	return entry
}

// WithFields creates an entry from the standard logger and adds multiple
// fields to it. This is simply a helper for `WithField`, invoking it
// once for each field.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithFields(fields map[string]interface{}) *Entry {
	entry := logf.withFields(Fields(fields), 1)
	return entry
}

func header(d int) *Entry {
	t := logf.GetTag()
	l := logf.GetLineInfo(depth + d)
	e := WithFields(Fields{
		tagKey: t,
		locKey: l,
	})
	return e
}

// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
	header(1).Debug(args...)
}

// Print logs a message at level Info on the standard logger.
func Print(args ...interface{}) {
	header(1).Print(args...)
}

// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
	header(1).Info(args...)
}

// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
	header(1).Warn(args...)
}

// Warning logs a message at level Warn on the standard logger.
func Warning(args ...interface{}) {
	header(1).Warning(args...)
}

// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
	header(1).Error(args...)
}

// Panic logs a message at level Panic on the standard logger.
func Panic(args ...interface{}) {
	header(1).Panic(args...)
}

// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
	header(1).Fatal(args...)
}

// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
	header(1).Debugf(format, args...)
}

// Printf logs a message at level Info on the standard logger.
func Printf(format string, args ...interface{}) {
	header(1).Printf(format, args...)
}

// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
	header(1).Infof(format, args...)
}

// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
	header(1).Warnf(format, args...)
}

// Warningf logs a message at level Warn on the standard logger.
func Warningf(format string, args ...interface{}) {
	header(1).Warningf(format, args...)
}

// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
	header(1).Errorf(format, args...)
}

// Panicf logs a message at level Panic on the standard logger.
func Panicf(format string, args ...interface{}) {
	header(1).Panicf(format, args...)
}

// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
	header(1).Fatalf(format, args...)
}

// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
	header(1).Debugln(args...)
}

// Println logs a message at level Info on the standard logger.
func Println(args ...interface{}) {
	header(1).Println(args...)
}

// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
	header(1).Infoln(args...)
}

// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
	header(1).Warnln(args...)
}

// Warningln logs a message at level Warn on the standard logger.
func Warningln(args ...interface{}) {
	header(1).Warningln(args...)
}

// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
	header(1).Errorln(args...)
}

// Panicln logs a message at level Panic on the standard logger.
func Panicln(args ...interface{}) {
	header(1).Panicln(args...)
}

// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
	header(1).Fatalln(args...)
}
<|endoftext|>


<commit_before>// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 model

import (
	"github.com/casbin/casbin/rbac"
	"github.com/casbin/casbin/util"
)

// BuildRoleLinks initializes the roles in RBAC.
func (model Model) BuildRoleLinks(rm rbac.RoleManager) {
	for _, ast := range model["g"] {
		ast.buildRoleLinks(rm)
	}
}

// PrintPolicy prints the policy to log.
func (model Model) PrintPolicy() {
	util.LogPrint("Policy:")
	for key, ast := range model["p"] {
		util.LogPrint(key, ": ", ast.Value, ": ", ast.Policy)
	}

	for key, ast := range model["g"] {
		util.LogPrint(key, ": ", ast.Value, ": ", ast.Policy)
	}
}

// ClearPolicy clears all current policy.
func (model Model) ClearPolicy() {
	for _, ast := range model["p"] {
		ast.Policy = nil
	}

	for _, ast := range model["g"] {
		ast.Policy = nil
	}
}

// GetPolicy gets all rules in a policy.
func (model Model) GetPolicy(sec string, ptype string) [][]string {
	return model[sec][ptype].Policy
}

// GetFilteredPolicy gets rules based on field filters from a policy.
func (model Model) GetFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) [][]string {
	res := [][]string{}

	for _, rule := range model[sec][ptype].Policy {
		matched := true
		for i, fieldValue := range fieldValues {
			if fieldValue != "" && rule[fieldIndex+i] != fieldValue {
				matched = false
				break
			}
		}

		if matched {
			res = append(res, rule)
		}
	}

	return res
}

// HasPolicy determines whether a model has the specified policy rule.
func (model Model) HasPolicy(sec string, ptype string, rule []string) bool {
	for _, r := range model[sec][ptype].Policy {
		if util.ArrayEquals(rule, r) {
			return true
		}
	}

	return false
}

// AddPolicy adds a policy rule to the model.
func (model Model) AddPolicy(sec string, ptype string, rule []string) bool {
	if !model.HasPolicy(sec, ptype, rule) {
		model[sec][ptype].Policy = append(model[sec][ptype].Policy, rule)
		return true
	}
	return false
}

// RemovePolicy removes a policy rule from the model.
func (model Model) RemovePolicy(sec string, ptype string, rule []string) bool {
	for i, r := range model[sec][ptype].Policy {
		if util.ArrayEquals(rule, r) {
			model[sec][ptype].Policy = append(model[sec][ptype].Policy[:i], model[sec][ptype].Policy[i+1:]...)
			return true
		}
	}

	return false
}

// RemoveFilteredPolicy removes policy rules based on field filters from the model.
func (model Model) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) bool {
	tmp := [][]string{}
	res := false
	for _, rule := range model[sec][ptype].Policy {
		matched := true
		for i, fieldValue := range fieldValues {
			if fieldValue != "" && rule[fieldIndex+i] != fieldValue {
				matched = false
				break
			}
		}

		if matched {
			res = true
		} else {
			tmp = append(tmp, rule)
		}
	}

	model[sec][ptype].Policy = tmp
	return res
}

// GetValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed.
func (model Model) GetValuesForFieldInPolicy(sec string, ptype string, fieldIndex int) []string {
	values := []string{}

	for _, rule := range model[sec][ptype].Policy {
		values = append(values, rule[fieldIndex])
	}

	util.ArrayRemoveDuplicates(&values)
	// sort.Strings(values)

	return values
}
<commit_msg>remove commented-out code<commit_after>// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 model

import (
	"github.com/casbin/casbin/rbac"
	"github.com/casbin/casbin/util"
)

// BuildRoleLinks initializes the roles in RBAC.
func (model Model) BuildRoleLinks(rm rbac.RoleManager) {
	for _, ast := range model["g"] {
		ast.buildRoleLinks(rm)
	}
}

// PrintPolicy prints the policy to log.
func (model Model) PrintPolicy() {
	util.LogPrint("Policy:")
	for key, ast := range model["p"] {
		util.LogPrint(key, ": ", ast.Value, ": ", ast.Policy)
	}

	for key, ast := range model["g"] {
		util.LogPrint(key, ": ", ast.Value, ": ", ast.Policy)
	}
}

// ClearPolicy clears all current policy.
func (model Model) ClearPolicy() {
	for _, ast := range model["p"] {
		ast.Policy = nil
	}

	for _, ast := range model["g"] {
		ast.Policy = nil
	}
}

// GetPolicy gets all rules in a policy.
func (model Model) GetPolicy(sec string, ptype string) [][]string {
	return model[sec][ptype].Policy
}

// GetFilteredPolicy gets rules based on field filters from a policy.
func (model Model) GetFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) [][]string {
	res := [][]string{}

	for _, rule := range model[sec][ptype].Policy {
		matched := true
		for i, fieldValue := range fieldValues {
			if fieldValue != "" && rule[fieldIndex+i] != fieldValue {
				matched = false
				break
			}
		}

		if matched {
			res = append(res, rule)
		}
	}

	return res
}

// HasPolicy determines whether a model has the specified policy rule.
func (model Model) HasPolicy(sec string, ptype string, rule []string) bool {
	for _, r := range model[sec][ptype].Policy {
		if util.ArrayEquals(rule, r) {
			return true
		}
	}

	return false
}

// AddPolicy adds a policy rule to the model.
func (model Model) AddPolicy(sec string, ptype string, rule []string) bool {
	if !model.HasPolicy(sec, ptype, rule) {
		model[sec][ptype].Policy = append(model[sec][ptype].Policy, rule)
		return true
	}
	return false
}

// RemovePolicy removes a policy rule from the model.
func (model Model) RemovePolicy(sec string, ptype string, rule []string) bool {
	for i, r := range model[sec][ptype].Policy {
		if util.ArrayEquals(rule, r) {
			model[sec][ptype].Policy = append(model[sec][ptype].Policy[:i], model[sec][ptype].Policy[i+1:]...)
			return true
		}
	}

	return false
}

// RemoveFilteredPolicy removes policy rules based on field filters from the model.
func (model Model) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) bool {
	tmp := [][]string{}
	res := false
	for _, rule := range model[sec][ptype].Policy {
		matched := true
		for i, fieldValue := range fieldValues {
			if fieldValue != "" && rule[fieldIndex+i] != fieldValue {
				matched = false
				break
			}
		}

		if matched {
			res = true
		} else {
			tmp = append(tmp, rule)
		}
	}

	model[sec][ptype].Policy = tmp
	return res
}

// GetValuesForFieldInPolicy gets all values for a field for all rules in a policy, duplicated values are removed.
func (model Model) GetValuesForFieldInPolicy(sec string, ptype string, fieldIndex int) []string {
	values := []string{}

	for _, rule := range model[sec][ptype].Policy {
		values = append(values, rule[fieldIndex])
	}

	util.ArrayRemoveDuplicates(&values)

	return values
}
<|endoftext|>


<commit_before>package usl

import "fmt"

// Measurement is a simultaneous measurement of at least two of the parameters of Little's Law:
// concurrency, throughput, and latency. The third parameter is inferred from the other two.
type Measurement struct {
	Concurrency float64
	Throughput  float64
	Latency     float64
}

func (m *Measurement) String() string {
	return fmt.Sprintf("(n=%v,x=%v,r=%v)", m.Concurrency, m.Throughput, m.Latency)
}

// ConcurrencyAndLatency returns a measurement of a system's latency at a given level of
// concurrency.
func ConcurrencyAndLatency(n, r float64) Measurement {
	return Measurement{
		Concurrency: n,
		Throughput:  n / r,
		Latency:     r,
	}
}

// ConcurrencyAndThroughput returns a measurement of a system's throughput at a given level of
// concurrency.
func ConcurrencyAndThroughput(n, x float64) Measurement {
	return Measurement{
		Concurrency: n,
		Throughput:  x,
		Latency:     n / x,
	}
}

// ThroughputAndLatency returns a measurement of a system's latency at a given level of throughput.
func ThroughputAndLatency(x, r float64) Measurement {
	return Measurement{
		Concurrency: x * r,
		Throughput:  x,
		Latency:     r,
	}
}
<commit_msg>docfix<commit_after>package usl

import "fmt"

// Measurement is a simultaneous measurement of at least two of the parameters of Little's Law:
// concurrency, throughput, and latency. The third parameter is inferred from the other two.
type Measurement struct {
	Concurrency float64 // The average number of concurrent events.
	Throughput  float64 // The long-term average arrival rate of events.
	Latency     float64 // The average duration of events.
}

func (m *Measurement) String() string {
	return fmt.Sprintf("(n=%v,x=%v,r=%v)", m.Concurrency, m.Throughput, m.Latency)
}

// ConcurrencyAndLatency returns a measurement of a system's latency at a given level of
// concurrency. The throughput of the system is derived via Little's Law.
func ConcurrencyAndLatency(n, r float64) Measurement {
	return Measurement{
		Concurrency: n,     // L
		Throughput:  n / r, // λ=L/W
		Latency:     r,     // W
	}
}

// ConcurrencyAndThroughput returns a measurement of a system's throughput at a given level of
// concurrency. The latency of the system is derived via Little's Law.
func ConcurrencyAndThroughput(n, x float64) Measurement {
	return Measurement{
		Concurrency: n,     // L
		Throughput:  x,     // λ
		Latency:     n / x, // W=L/λ
	}
}

// ThroughputAndLatency returns a measurement of a system's latency at a given level of throughput.
// The concurrency of the system is derived via Little's Law.
func ThroughputAndLatency(x, r float64) Measurement {
	return Measurement{
		Concurrency: x * r, // L=λW
		Throughput:  x,     // λ
		Latency:     r,     // W
	}
}
<|endoftext|>


<commit_before>package chalmers_chop

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/mmcdole/gofeed"
	"strings"
)

func ParseWeeklyFeed(feed *gofeed.Feed) []Menu {
	var menus []Menu

	for _, item := range feed.Items {
		var menu Menu

		menu.Title = item.Title
		menu.Date = parseDate(item)
		menu.Dishes = parseDishes(item)

		menus = append(menus, menu)
	}

	return menus
}

func parseDate(item *gofeed.Item) string {
	// Date is always the last 10 characters of the Title property in the format
	// YYYY-mm-dd
	t := item.Title
	return string(t[len(t)-10:])
}

/*
Searches the contents of the item <description> tag for dishes

The <description> tag contains a single
 element, for example:

      Hamburger of the Day

      Beef, wheat bread, french fries

Each
 represents a single dish.
Each dish has at least two .

The first  contains the dish name, surrounded by a  tag
The second  contains the dish contents

Dish price and allergy information is not available in the source data
*/
func parseDishes(item *gofeed.Item) []Dish {
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(item.Description))

	if err != nil {
		panic(err)
	}

	var dishes []Dish

	doc.Find("table tr").Each(func(i int, tr *goquery.Selection) {
		var dish Dish

		td := tr.Find("td")

		dish.Name = td.Eq(0).Children().First().Text()
		dish.Contents = td.Eq(1).Text()

		dishes = append(dishes, dish)
	})

	return dishes
}
<commit_msg>Move declaration<commit_after>package chalmers_chop

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/mmcdole/gofeed"
	"strings"
)

func ParseWeeklyFeed(feed *gofeed.Feed) []Menu {
	var menus []Menu

	for _, item := range feed.Items {
		var menu Menu

		menu.Title = item.Title
		menu.Date = parseDate(item)
		menu.Dishes = parseDishes(item)

		menus = append(menus, menu)
	}

	return menus
}

func parseDate(item *gofeed.Item) string {
	// Date is always the last 10 characters of the Title property in the format
	// YYYY-mm-dd
	t := item.Title
	return string(t[len(t)-10:])
}

/*
Searches the contents of the item <description> tag for dishes

The <description> tag contains a single
 element, for example:

      Hamburger of the Day

      Beef, wheat bread, french fries

Each
 represents a single dish.
Each dish has at least two .

The first  contains the dish name, surrounded by a  tag
The second  contains the dish contents

Dish price and allergy information is not available in the source data
*/
func parseDishes(item *gofeed.Item) []Dish {
	var dishes []Dish
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(item.Description))

	if err != nil {
		panic(err)
	}

	doc.Find("table tr").Each(func(i int, tr *goquery.Selection) {
		var dish Dish

		td := tr.Find("td")

		dish.Name = td.Eq(0).Children().First().Text()
		dish.Contents = td.Eq(1).Text()

		dishes = append(dishes, dish)
	})

	return dishes
}
<|endoftext|>