<commit_before>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2017 Charles University, Faculty of Arts,
//                Institute of the Czech National Corpus
//
// 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 main

import (
	"flag"
	"log"
	"os"
	"time"

	"github.com/czcorpus/vert-tagextract/db"
	"github.com/czcorpus/vert-tagextract/db/colgen"
	"github.com/czcorpus/vert-tagextract/vteconf"
	"github.com/tomachalek/vertigo"
)

func main() {
	updateOnly := flag.Bool("update", false, "Update an existing schema, do not delete existing rows (useful e.g. for Intercorp)")
	flag.Parse()
	if len(flag.Args()) != 1 {
		log.Fatal("Unknown command, a config file must be specified")
	}
	conf := vteconf.LoadConf(flag.Arg(0))

	_, ferr := os.Stat(conf.DBFile)
	if os.IsNotExist(ferr) {
		if *updateOnly {
			log.Fatalf("Update flag is set but the database %s does not exist", conf.DBFile)
		}

	} else if !*updateOnly {
		log.Printf("The database file %s already exists. Existing data will be deleted.", conf.DBFile)
	}
	dbConn := db.OpenDatabase(conf.DBFile)

	if !*updateOnly {
		db.DropExisting(dbConn)
		db.CreateSchema(dbConn, conf)
		if conf.HasConfiguredBib() {
			db.CreateBibView(dbConn, conf)
		}
	}

	parserConf := &vertigo.ParserConf{
		VerticalFilePath:      conf.VerticalFile,
		StructAttrAccumulator: "nil",
	}

	var fn colgen.AlignedColGenFn
	if conf.UsesSelfJoin() {
		fn = func(args map[string]interface{}) string {
			return colgen.GetFuncByName(conf.SelfJoin.GeneratorFn)(args, conf.SelfJoin.ArgColumns)
		}
	}

	tte := db.NewTTExtractor(dbConn, conf.Corpus, conf.AtomStructure, conf.Structures, fn)
	t0 := time.Now()
	tte.Run(parserConf)
	log.Printf("Finished in %s seconds.\n", time.Since(t0))
}
<commit_msg>Pass encoding info to Vertigo parser<commit_after>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2017 Charles University, Faculty of Arts,
//                Institute of the Czech National Corpus
//
// 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 main

import (
	"flag"
	"log"
	"os"
	"time"

	"github.com/czcorpus/vert-tagextract/db"
	"github.com/czcorpus/vert-tagextract/db/colgen"
	"github.com/czcorpus/vert-tagextract/vteconf"
	"github.com/tomachalek/vertigo"
)

func main() {
	updateOnly := flag.Bool("update", false, "Update an existing schema, do not delete existing rows (useful e.g. for Intercorp)")
	flag.Parse()
	if len(flag.Args()) != 1 {
		log.Fatal("Unknown command, a config file must be specified")
	}
	conf := vteconf.LoadConf(flag.Arg(0))

	_, ferr := os.Stat(conf.DBFile)
	if os.IsNotExist(ferr) {
		if *updateOnly {
			log.Fatalf("Update flag is set but the database %s does not exist", conf.DBFile)
		}

	} else if !*updateOnly {
		log.Printf("The database file %s already exists. Existing data will be deleted.", conf.DBFile)
	}
	dbConn := db.OpenDatabase(conf.DBFile)

	if !*updateOnly {
		db.DropExisting(dbConn)
		db.CreateSchema(dbConn, conf)
		if conf.HasConfiguredBib() {
			db.CreateBibView(dbConn, conf)
		}
	}

	parserConf := &vertigo.ParserConf{
		VerticalFilePath:      conf.VerticalFile,
		StructAttrAccumulator: "nil",
		Encoding:              conf.Encoding,
	}

	var fn colgen.AlignedColGenFn
	if conf.UsesSelfJoin() {
		fn = func(args map[string]interface{}) string {
			return colgen.GetFuncByName(conf.SelfJoin.GeneratorFn)(args, conf.SelfJoin.ArgColumns)
		}
	}

	tte := db.NewTTExtractor(dbConn, conf.Corpus, conf.AtomStructure, conf.Structures, fn)
	t0 := time.Now()
	tte.Run(parserConf)
	log.Printf("Finished in %s seconds.\n", time.Since(t0))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/SyntropyDev/mms-api/model"
	"github.com/SyntropyDev/mms-api/mware"
	"github.com/SyntropyDev/sqlutil"
	"github.com/bmizerany/pat"
	"github.com/coopernurse/gorp"
	_ "github.com/go-sql-driver/mysql"
	"github.com/lann/squirrel"
)

const (
	prefix = "/api/v1"
)

func main() {
	m := pat.New()
	m.Get(prefix+"/community", serveFile("public/community.json"))

	m.Get(prefix+"/members", mware.GetAll(&model.Member{}))
	m.Get(prefix+"/members/:id", mware.GetByID(&model.Member{}))

	m.Get(prefix+"/categories", mware.GetAll(&model.Category{}))
	m.Get(prefix+"/categories/:id", mware.GetByID(&model.Category{}))

	m.Get(prefix+"/stories", mware.GetAll(&model.Story{}))
	m.Get(prefix+"/stories/:id", mware.GetByID(&model.Story{}))

	http.Handle("/", m)

	mware.SetGetDBConnectionFunc(db)

	// listen to feeds in a background thread
	go func() {
		for {
			if err := listenToFeeds(); err != nil {
				log.Println("feed listening error: ", err)
			}
			time.Sleep(time.Minute * 5)
		}
	}()

	log.Println("Listening...")
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}

func listenToFeeds() error {
	dbmap, err := db()
	if err != nil {
		return err
	}

	feeds := []*model.Feed{}
	query := squirrel.Select("*").From(model.TableNameFeed)
	if err := sqlutil.Select(dbmap, query, &feeds); err != nil {
		return err
	}

	for _, feed := range feeds {
		feed.UpdateStories(dbmap)
	}

	return nil
}

func db() (*gorp.DbMap, error) {
	db, err := sql.Open("mysql", os.Getenv("DATABASE_URL"))
	if err != nil {
		return nil, err
	}
	dbmap := &gorp.DbMap{
		Db:      db,
		Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
	}
	dbmap.AddTableWithName(model.Category{}, model.TableNameCategory).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Feed{}, model.TableNameFeed).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Story{}, model.TableNameStory).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Member{}, model.TableNameMember).SetKeys(true, "ID")

	if err := dbmap.CreateTablesIfNotExists(); err != nil {
		return nil, err
	}

	return dbmap, nil
}

func serveFile(name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, name)
	})
}
<commit_msg>logging<commit_after>package main

import (
	"database/sql"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/SyntropyDev/mms-api/model"
	"github.com/SyntropyDev/mms-api/mware"
	"github.com/SyntropyDev/sqlutil"
	"github.com/bmizerany/pat"
	"github.com/coopernurse/gorp"
	_ "github.com/go-sql-driver/mysql"
	"github.com/lann/squirrel"
)

const (
	prefix = "/api/v1"
)

func main() {
	m := pat.New()
	m.Get(prefix+"/community", serveFile("public/community.json"))

	m.Get(prefix+"/members", mware.GetAll(&model.Member{}))
	m.Get(prefix+"/members/:id", mware.GetByID(&model.Member{}))

	m.Get(prefix+"/categories", mware.GetAll(&model.Category{}))
	m.Get(prefix+"/categories/:id", mware.GetByID(&model.Category{}))

	m.Get(prefix+"/stories", mware.GetAll(&model.Story{}))
	m.Get(prefix+"/stories/:id", mware.GetByID(&model.Story{}))

	http.Handle("/", m)

	mware.SetGetDBConnectionFunc(db)

	// listen to feeds in a background thread
	go func() {
		for {
			if err := listenToFeeds(); err != nil {
				log.Println("feed listening error: ", err)
			}
			time.Sleep(time.Minute * 5)
		}
	}()

	log.Println("Listening...")
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}

func listenToFeeds() error {
	dbmap, err := db()
	if err != nil {
		return err
	}

	feeds := []*model.Feed{}
	query := squirrel.Select("*").From(model.TableNameFeed)
	if err := sqlutil.Select(dbmap, query, &feeds); err != nil {
		return err
	}

	for _, feed := range feeds {
		feed.UpdateStories(dbmap)
	}

	return nil
}

func db() (*gorp.DbMap, error) {
	db, err := sql.Open("mysql", os.Getenv("DATABASE_URL"))
	if err != nil {
		return nil, err
	} else {
		log.Println("Database Connection Established")
	}

	dbmap := &gorp.DbMap{
		Db:      db,
		Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
	}

	dbmap.AddTableWithName(model.Category{}, model.TableNameCategory).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Feed{}, model.TableNameFeed).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Story{}, model.TableNameStory).SetKeys(true, "ID")
	dbmap.AddTableWithName(model.Member{}, model.TableNameMember).SetKeys(true, "ID")

	if err := dbmap.CreateTablesIfNotExists(); err != nil {
		return nil, err
	}

	return dbmap, nil
}

func serveFile(name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, name)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"

	"github.com/go-martini/martini"
	"github.com/joshuarubin/goscribe/telapi"
	"github.com/kr/pretty"
	"github.com/martini-contrib/auth"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/strict"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

// TODO(jrubin):
// * mgo (http://labix.org/mgo)
// * sessions (https://github.com/martini-contrib/sessions)
// * oauth2 (https://github.com/martini-contrib/oauth2)
// * accessflags (https://github.com/martini-contrib/accessflags)
// * remove auth, replace with api key validator (github.com/martini-contrib/auth)
// * CORS support would be nice (https://github.com/martini-contrib/cors)
// * CSRF (https://github.com/martini-contrib/csrf)
// * secure (https://github.com/martini-contrib/secure)

var (
	m         *martini.ClassicMartini
	s3Bucket  *s3.Bucket
	s3BaseURL string
	baseURL   string
	authUser  string
	authPass  string
)

type callbackData struct {
	CallbackURL string `form:"callback_url" binding:"required"`
}

type transcribeData struct {
	callbackData
	AudioURL string `form:"audio_url" binding:"required"`
}

type transcribeUploadData struct {
	callbackData
	AudioData *multipart.FileHeader `form:"audio_data" binding:"required"`
}

func init() {
	// BASE_URL, AUTH_USER and AUTH_PASS, AWS_S3_BASE_URL are not required or else wercker tests would fail
	baseURL = os.Getenv("BASE_URL")
	authUser = os.Getenv("AUTH_USER")
	authPass = os.Getenv("AUTH_PASS")
	s3BaseURL = os.Getenv("AWS_S3_BASE_URL")

	if awsAuth, err := aws.EnvAuth(); err != nil {
		// not required or else wercker tests would fail
		log.Println(err)
	} else {
		// TODO(jrubin) allow region to be chosen by env variable
		s3Data := s3.New(awsAuth, aws.USWest2)
		s3Bucket = s3Data.Bucket(os.Getenv("AWS_S3_BUCKET_NAME"))
	}

	m = martini.Classic()

	m.Use(gzip.All())
	m.Use(render.Renderer())

	m.Get("/", func() string {
		return "hello, world"
	})

	m.Post(
		"/v1/transcribe",
		auth.Basic(authUser, authPass),
		strict.Accept("application/json"),
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(transcribeData{}),
		binding.ErrorHandler,
		handleTranscribe,
	)

	m.Post(
		"/v1/transcribe/process",
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(telapi.TranscribeCallbackData{}),
		binding.ErrorHandler,
		handleTranscribeProcess,
	)

	m.Post(
		"/v1/transcribe/upload",
		auth.Basic(authUser, authPass),
		strict.Accept("application/json"),
		binding.MultipartForm(transcribeUploadData{}),
		binding.ErrorHandler,
		handleTranscribeUpload,
	)

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
}

func main() {
	m.Run()
}

func success(r render.Render, data ...interface{}) {
	ret := map[string]interface{}{
		"status": http.StatusOK,
	}

	l := len(data)
	if l == 1 {
		ret["data"] = data[0]
	} else if l > 1 {
		ret["data"] = data
	}

	r.JSON(http.StatusOK, ret)
}

func jsonError(r render.Render, status int, err error) {
	r.JSON(status, map[string]interface{}{
		"status": status,
		"error":  err.Error(),
	})
}

func telapiError(r render.Render, err error) {
	if telapiError, ok := err.(telapi.Error); ok {
		r.JSON(telapiError.JSON())
		return
	}

	jsonError(r, http.StatusInternalServerError, err)
}

func transcribe(r render.Render, url, callback string) {
	resp, err := telapi.TranscribeURL(url, callback)
	if err != nil {
		telapiError(r, err)
		return
	}

	success(r, resp.TranscribeClientResponse.Translate())
}

func s3Upload(basePath string, data *multipart.FileHeader) (string, error) {
	fileName := data.Filename
	fileType := data.Header.Get("Content-Type")

	file, err := data.Open()
	defer file.Close()

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

	fileData, err := ioutil.ReadAll(file)
	if err != nil {
		return "", err
	}

	filePath := fmt.Sprintf("/%s/%s", basePath, fileName)

	if err := s3Bucket.Put(filePath, fileData, fileType, s3.PublicRead); err != nil {
		return "", err
	}

	return s3BaseURL + filePath, nil
}

func handleTranscribe(data transcribeData, r render.Render) {
	transcribe(r, data.AudioURL, data.CallbackURL)
}

func handleTranscribeProcess(data telapi.TranscribeCallbackData, r render.Render) {
	pretty.Println(data)
	b, _ := json.Marshal(data.TranscribeCallbackClientData)
	pretty.Println(string(b))
	success(r)
}

func handleTranscribeUpload(data transcribeUploadData, r render.Render) {
	fileURL, err := s3Upload("audio", data.AudioData)
	if err != nil {
		jsonError(r, http.StatusInternalServerError, err)
		return
	}

	transcribe(r, fileURL, data.CallbackURL)
}
<commit_msg>use sha1 to prefix filename for uniqueness<commit_after>package main

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"

	"github.com/go-martini/martini"
	"github.com/joshuarubin/goscribe/telapi"
	"github.com/kr/pretty"
	"github.com/martini-contrib/auth"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/strict"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

// TODO(jrubin):
// * mgo (http://labix.org/mgo)
// * sessions (https://github.com/martini-contrib/sessions)
// * oauth2 (https://github.com/martini-contrib/oauth2)
// * accessflags (https://github.com/martini-contrib/accessflags)
// * remove auth, replace with api key validator (github.com/martini-contrib/auth)
// * CORS support would be nice (https://github.com/martini-contrib/cors)
// * CSRF (https://github.com/martini-contrib/csrf)
// * secure (https://github.com/martini-contrib/secure)

var (
	m         *martini.ClassicMartini
	s3Bucket  *s3.Bucket
	s3BaseURL string
	baseURL   string
	authUser  string
	authPass  string
)

type callbackData struct {
	CallbackURL string `form:"callback_url" binding:"required"`
}

type transcribeData struct {
	callbackData
	AudioURL string `form:"audio_url" binding:"required"`
}

type transcribeUploadData struct {
	callbackData
	AudioData *multipart.FileHeader `form:"audio_data" binding:"required"`
}

func init() {
	// BASE_URL, AUTH_USER and AUTH_PASS, AWS_S3_BASE_URL are not required or else wercker tests would fail
	baseURL = os.Getenv("BASE_URL")
	authUser = os.Getenv("AUTH_USER")
	authPass = os.Getenv("AUTH_PASS")
	s3BaseURL = os.Getenv("AWS_S3_BASE_URL")

	if awsAuth, err := aws.EnvAuth(); err != nil {
		// not required or else wercker tests would fail
		log.Println(err)
	} else {
		// TODO(jrubin) allow region to be chosen by env variable
		s3Data := s3.New(awsAuth, aws.USWest2)
		s3Bucket = s3Data.Bucket(os.Getenv("AWS_S3_BUCKET_NAME"))
	}

	m = martini.Classic()

	m.Use(gzip.All())
	m.Use(render.Renderer())

	m.Get("/", func() string {
		return "hello, world"
	})

	m.Post(
		"/v1/transcribe",
		auth.Basic(authUser, authPass),
		strict.Accept("application/json"),
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(transcribeData{}),
		binding.ErrorHandler,
		handleTranscribe,
	)

	m.Post(
		"/v1/transcribe/process",
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(telapi.TranscribeCallbackData{}),
		binding.ErrorHandler,
		handleTranscribeProcess,
	)

	m.Post(
		"/v1/transcribe/upload",
		auth.Basic(authUser, authPass),
		strict.Accept("application/json"),
		binding.MultipartForm(transcribeUploadData{}),
		binding.ErrorHandler,
		handleTranscribeUpload,
	)

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
}

func main() {
	m.Run()
}

func success(r render.Render, data ...interface{}) {
	ret := map[string]interface{}{
		"status": http.StatusOK,
	}

	l := len(data)
	if l == 1 {
		ret["data"] = data[0]
	} else if l > 1 {
		ret["data"] = data
	}

	r.JSON(http.StatusOK, ret)
}

func jsonError(r render.Render, status int, err error) {
	r.JSON(status, map[string]interface{}{
		"status": status,
		"error":  err.Error(),
	})
}

func telapiError(r render.Render, err error) {
	if telapiError, ok := err.(telapi.Error); ok {
		r.JSON(telapiError.JSON())
		return
	}

	jsonError(r, http.StatusInternalServerError, err)
}

func transcribe(r render.Render, url, callback string) {
	resp, err := telapi.TranscribeURL(url, callback)
	if err != nil {
		telapiError(r, err)
		return
	}

	success(r, resp.TranscribeClientResponse.Translate())
}

func s3Upload(basePath string, data *multipart.FileHeader) (string, error) {
	fileName := data.Filename
	fileType := data.Header.Get("Content-Type")

	file, err := data.Open()
	defer file.Close()

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

	fileData, err := ioutil.ReadAll(file)
	if err != nil {
		return "", err
	}

	h := sha1.New()
	if _, err := h.Write(fileData); err != nil {
		return "", err
	}

	filePath := fmt.Sprintf("/%s/%x_%s", basePath, h.Sum(nil), fileName)

	if err := s3Bucket.Put(filePath, fileData, fileType, s3.PublicRead); err != nil {
		return "", err
	}

	return s3BaseURL + filePath, nil
}

func handleTranscribe(data transcribeData, r render.Render) {
	transcribe(r, data.AudioURL, data.CallbackURL)
}

func handleTranscribeProcess(data telapi.TranscribeCallbackData, r render.Render) {
	pretty.Println(data)
	b, _ := json.Marshal(data.TranscribeCallbackClientData)
	pretty.Println(string(b))
	success(r)
}

func handleTranscribeUpload(data transcribeUploadData, r render.Render) {
	fileURL, err := s3Upload("audio", data.AudioData)
	if err != nil {
		jsonError(r, http.StatusInternalServerError, err)
		return
	}

	transcribe(r, fileURL, data.CallbackURL)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/joho/godotenv"
	"gopkg.in/mgo.v2"
	"log"
	"net/http"
	"os"
	// "gopkg.in/mgo.v2/bson"
)

const DefaultPort = ":3000"
const EnvPort = "PORT"
const DatabaseName = "beerserver"

func main() {
	// Load environmental variables.
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}

	// Connect to database.
	session, err := mgo.Dial(os.Getenv("MONGOLAB_URI"))
	if err != nil {
		panic(err)
	}
	defer session.Close()
	// ??
	session.SetMode(mgo.Monotonic, true)

	// Set up router.
	routes := NewRoutes(session.DB(DatabaseName))
	router := NewRouter()
	router.GET("/", routes.Index)
	router.GET("/channels", routes.GetChannels)
	router.POST("/channels", routes.CreateChannel)
	router.GET("/channels/{id}", routes.GetChannel)
	router.GET("/channels/{channelId}/datapoints", routes.GetDatapoints)
	router.POST("/channels/{channelId}/datapoints", routes.CreateDatapoint)

	// Start server.
	port := DefaultPort
	if os.Getenv(EnvPort) != "" {
		port = ":" + os.Getenv(EnvPort)
	}
	log.Fatal(http.ListenAndServe(port, router))

	log.Println("Listening on %v", port)
}
<commit_msg>Ignore even if .env doesn't exist.<commit_after>package main

import (
	"github.com/joho/godotenv"
	"gopkg.in/mgo.v2"
	"log"
	"net/http"
	"os"
	// "gopkg.in/mgo.v2/bson"
)

const DefaultPort = ":3000"
const EnvPort = "PORT"
const DatabaseName = "beerserver"

func main() {
	// Load environmental variables.
	err := godotenv.Load()
	if err != nil {
		log.Println("Couldn't read .env file")
	}

	// Connect to database.
	session, err := mgo.Dial(os.Getenv("MONGOLAB_URI"))
	if err != nil {
		panic(err)
	}
	defer session.Close()
	// ??
	session.SetMode(mgo.Monotonic, true)

	// Set up router.
	routes := NewRoutes(session.DB(DatabaseName))
	router := NewRouter()
	router.GET("/", routes.Index)
	router.GET("/channels", routes.GetChannels)
	router.POST("/channels", routes.CreateChannel)
	router.GET("/channels/{id}", routes.GetChannel)
	router.GET("/channels/{channelId}/datapoints", routes.GetDatapoints)
	router.POST("/channels/{channelId}/datapoints", routes.CreateDatapoint)

	// Start server.
	port := DefaultPort
	if os.Getenv(EnvPort) != "" {
		port = ":" + os.Getenv(EnvPort)
	}
	log.Fatal(http.ListenAndServe(port, router))

	log.Println("Listening on %v", port)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"

	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
)

type Device struct {
	Name      string `json:"name"`
	HouseCode string `json:"house_code"`
	DeviceID  int    `json:"device_id"`
	Dimmable  bool   `json:"dimmable"`
}

func X10Devices() []*accessory.Accessory {
	file, err := ioutil.ReadFile("./config/x10.json")
	if err != nil {
		log.Fatalln("Error opening X10 config file", err.Error())
	}

	var bulbs []Device
	if err = json.Unmarshal(file, &bulbs); err != nil {
		log.Fatalln("Error parsing X10 config file", err.Error())
	}

	lightBulbs := []interface{}{}

	for _, b := range bulbs {
		var device Device = b
		log.Printf("Creating X10 accessory \"%v\"...\n", device.Name)

		info := model.Info{
			Name:         device.Name,
			Manufacturer: "X10",
		}

		light := accessory.NewLightBulb(info)
		light.OnStateChanged(func(on bool) {
			var action string
			if on {
				action = "on"
			} else {
				action = "off"
			}
			var method string
			if device.Dimmable {
				method = "pl"
			} else {
				method = "rf"
			}

			cmd := fmt.Sprintf("%s %s%v %s", method, device.HouseCode, device.DeviceID, action)
			writeCommand(cmd)
		})
		light.OnBrightnessChanged(func(val int) {
			if device.Dimmable {
				dimVal := int((float64(val) / 100) * 70)
				cmd := fmt.Sprintf("pl %s%v xdim %v", device.HouseCode, device.DeviceID, dimVal)
				writeCommand(cmd)
			}
		})

		lightBulbs = append(lightBulbs, light.Accessory)
	}

	accessories := make([]*accessory.Accessory, len(lightBulbs))
	for i, bulb := range lightBulbs {
		accessories[i] = bulb.(*accessory.Accessory)
	}

	return accessories
}

func writeCommand(cmd string) {
	// TODO: Queue commands and execute serially with a delay
	log.Printf("Writing command \"%s\"", cmd)
	conn, err := net.Dial("tcp", "localhost:1099")
	if err != nil {
		log.Println(err)
	}
	defer conn.Close()

	_, err = conn.Write([]byte(cmd + "\n"))
	if err != nil {
		log.Println(err)
	}
}
<commit_msg>idk what i was doing<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"

	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
)

type Device struct {
	Name      string `json:"name"`
	HouseCode string `json:"house_code"`
	DeviceID  int    `json:"device_id"`
	Dimmable  bool   `json:"dimmable"`
}

func X10Devices() []*accessory.Accessory {
	file, err := ioutil.ReadFile("./config/x10.json")
	if err != nil {
		log.Fatalln("Error opening X10 config file", err.Error())
	}

	var bulbs []Device
	if err = json.Unmarshal(file, &bulbs); err != nil {
		log.Fatalln("Error parsing X10 config file", err.Error())
	}

	lightBulbs := []*accessory.Accessory{}

	for _, b := range bulbs {
		var device Device = b
		log.Printf("Creating X10 accessory \"%v\"...\n", device.Name)

		info := model.Info{
			Name:         device.Name,
			Manufacturer: "X10",
		}

		light := accessory.NewLightBulb(info)
		light.OnStateChanged(func(on bool) {
			var action string
			if on {
				action = "on"
			} else {
				action = "off"
			}
			var method string
			if device.Dimmable {
				method = "pl"
			} else {
				method = "rf"
			}

			cmd := fmt.Sprintf("%s %s%v %s", method, device.HouseCode, device.DeviceID, action)
			writeCommand(cmd)
		})
		light.OnBrightnessChanged(func(val int) {
			if device.Dimmable {
				dimVal := int((float64(val) / 100) * 70)
				cmd := fmt.Sprintf("pl %s%v xdim %v", device.HouseCode, device.DeviceID, dimVal)
				writeCommand(cmd)
			}
		})

		lightBulbs = append(lightBulbs, light.Accessory)
	}

	return lightBulbs
}

func writeCommand(cmd string) {
	// TODO: Queue commands and execute serially with a delay
	log.Printf("Writing command \"%s\"", cmd)
	conn, err := net.Dial("tcp", "localhost:1099")
	if err != nil {
		log.Println(err)
	}
	defer conn.Close()

	_, err = conn.Write([]byte(cmd + "\n"))
	if err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 VMware, Inc. 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 dao

import (
	"fmt"
	"testing"

	"github.com/vmware/harbor/src/common/models"
)

func TestDeleteProject(t *testing.T) {
	name := "project_for_test"
	project := models.Project{
		OwnerID: currentUser.UserID,
		Name:    name,
	}

	id, err := AddProject(project)
	if err != nil {
		t.Fatalf("failed to add project: %v", err)
	}
	defer func() {
		if err := delProjPermanent(id); err != nil {
			t.Errorf("failed to clear up project %d: %v", id, err)
		}
	}()

	if err = DeleteProject(id); err != nil {
		t.Fatalf("failed to delete project: %v", err)
	}

	p := &models.Project{}
	if err = GetOrmer().Raw(`select * from project where project_id = ?`, id).
		QueryRow(p); err != nil {
		t.Fatalf("failed to get project: %v", err)
	}

	if p.Deleted != 1 {
		t.Errorf("unexpeced deleted column: %d != %d", p.Deleted, 1)
	}

	deletedName := fmt.Sprintf("%s#%d", name, id)
	if p.Name != deletedName {
		t.Errorf("unexpected name: %s != %s", p.Name, deletedName)
	}

}

func delProjPermanent(id int64) error {
	_, err := GetOrmer().QueryTable("access_log").
		Filter("ProjectID", id).
		Delete()
	if err != nil {
		return err
	}

	_, err = GetOrmer().Raw(`delete from project_member
		where project_id = ?`, id).Exec()
	if err != nil {
		return err
	}

	_, err = GetOrmer().QueryTable("project").
		Filter("ProjectID", id).
		Delete()
	return err
}
<commit_msg>Add UT<commit_after>// Copyright (c) 2017 VMware, Inc. 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 dao

import (
	"fmt"
	"strings"
	"testing"

	"github.com/vmware/harbor/src/common/models"
)

func TestDeleteProject(t *testing.T) {
	name := "project_for_test"
	project := models.Project{
		OwnerID: currentUser.UserID,
		Name:    name,
	}

	id, err := AddProject(project)
	if err != nil {
		t.Fatalf("failed to add project: %v", err)
	}
	defer func() {
		if err := delProjPermanent(id); err != nil {
			t.Errorf("failed to clear up project %d: %v", id, err)
		}
	}()

	if err = DeleteProject(id); err != nil {
		t.Fatalf("failed to delete project: %v", err)
	}

	p := &models.Project{}
	if err = GetOrmer().Raw(`select * from project where project_id = ?`, id).
		QueryRow(p); err != nil {
		t.Fatalf("failed to get project: %v", err)
	}

	if p.Deleted != 1 {
		t.Errorf("unexpeced deleted column: %d != %d", p.Deleted, 1)
	}

	deletedName := fmt.Sprintf("%s#%d", name, id)
	if p.Name != deletedName {
		t.Errorf("unexpected name: %s != %s", p.Name, deletedName)
	}

}

func delProjPermanent(id int64) error {
	_, err := GetOrmer().QueryTable("access_log").
		Filter("ProjectID", id).
		Delete()
	if err != nil {
		return err
	}

	_, err = GetOrmer().Raw(`delete from project_member
		where project_id = ?`, id).Exec()
	if err != nil {
		return err
	}

	_, err = GetOrmer().QueryTable("project").
		Filter("ProjectID", id).
		Delete()
	return err
}

func Test_projectQueryConditions(t *testing.T) {
	type args struct {
		query *models.ProjectQueryParam
	}
	tests := []struct {
		name  string
		args  args
		want  string
		want1 []interface{}
	}{
		{"Query invalid projectID",
			args{query: &models.ProjectQueryParam{ProjectIDs: []int64{}, Owner: "admin"}},
			"from project as p where 1 = 0",
			[]interface{}{}},
		{"Query with valid projectID",
			args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin"}},
			` from project as p join user u1
					on p.owner_id = u1.user_id where p.deleted=0 and u1.username=? and p.project_id in ( ?,? ) order by p.name`,
			[]interface{}{2, 3}},
		{"Query with valid page and member",
			args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin", Name: "sample", Member: &models.MemberQuery{Name: "name", Role: 1}, Pagination: &models.Pagination{Page: 1, Size: 20}}},
			` from project as p join user u1
					on p.owner_id = u1.user_id join project_member pm
					on p.project_id = pm.project_id
					join user u2
					on pm.entity_id=u2.user_id where p.deleted=0 and u1.username=? and p.name like ? and u2.username=? and pm.role = ? and p.project_id in ( ?,? ) order by p.name limit ? offset ?`,
			[]interface{}{1, []int64{2, 3}, 20, 0}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, _ := projectQueryConditions(tt.args.query)
			if strings.TrimSpace(got) != strings.TrimSpace(tt.want) {
				t.Errorf("projectQueryConditions() got = %v\n, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 Dgraph Labs, Inc. and Contributors
 *
 * 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 z

import (
	"context"
	"sync"

	"github.com/cespare/xxhash"
)

// TODO: Figure out a way to re-use memhash for the second uint64 hash, we
//       already know that appending bytes isn't reliable for generating a
//       second hash (see Ristretto PR #88).
//
//       We also know that while the Go runtime has a runtime memhash128
//       function, it's not possible to use it to generate [2]uint64 or
//       anything resembling a 128bit hash, even though that's exactly what
//       we need in this situation.
func KeyToHash(key interface{}) (uint64, uint64) {
	if key == nil {
		return 0, 0
	}
	switch k := key.(type) {
	case uint64:
		return k, 0
	case string:
		return MemHashString(k), xxhash.Sum64String(k)
	case []byte:
		return MemHash(k), xxhash.Sum64(k)
	case byte:
		return uint64(k), 0
	case int:
		return uint64(k), 0
	case int32:
		return uint64(k), 0
	case uint32:
		return uint64(k), 0
	case int64:
		return uint64(k), 0
	default:
		panic("Key type not supported")
	}
}

var (
	dummyCloserChan <-chan struct{}
)

// Closer holds the two things we need to close a goroutine and wait for it to
// finish: a chan to tell the goroutine to shut down, and a WaitGroup with
// which to wait for it to finish shutting down.
type Closer struct {
	waiting sync.WaitGroup

	ctx    context.Context
	cancel context.CancelFunc
}

// NewCloser constructs a new Closer, with an initial count on the WaitGroup.
func NewCloser(initial int) *Closer {
	ret := &Closer{}
	ret.ctx, ret.cancel = context.WithCancel(context.Background())
	ret.waiting.Add(initial)
	return ret
}

// AddRunning Add()'s delta to the WaitGroup.
func (lc *Closer) AddRunning(delta int) {
	lc.waiting.Add(delta)
}

// Ctx can be used to get a context, which would automatically get cancelled when Signal is called.
func (lc *Closer) Ctx() context.Context {
	if lc == nil {
		return context.Background()
	}
	return lc.ctx
}

// Signal signals the HasBeenClosed signal.
func (lc *Closer) Signal() {
	// Todo(ibrahim): Change Signal to return error on next badger breaking change.
	lc.cancel()
}

// HasBeenClosed gets signaled when Signal() is called.
func (lc *Closer) HasBeenClosed() <-chan struct{} {
	if lc == nil {
		return dummyCloserChan
	}
	return lc.ctx.Done()
}

// Done calls Done() on the WaitGroup.
func (lc *Closer) Done() {
	if lc == nil {
		return
	}
	lc.waiting.Done()
}

// Wait waits on the WaitGroup. (It waits for NewCloser's initial value, AddRunning, and Done
// calls to balance out.)
func (lc *Closer) Wait() {
	lc.waiting.Wait()
}

// SignalAndWait calls Signal(), then Wait().
func (lc *Closer) SignalAndWait() {
	lc.Signal()
	lc.Wait()
}
<commit_msg>Add ZeroOut func<commit_after>/*
 * Copyright 2019 Dgraph Labs, Inc. and Contributors
 *
 * 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 z

import (
	"context"
	"sync"

	"github.com/cespare/xxhash"
)

// TODO: Figure out a way to re-use memhash for the second uint64 hash, we
//       already know that appending bytes isn't reliable for generating a
//       second hash (see Ristretto PR #88).
//
//       We also know that while the Go runtime has a runtime memhash128
//       function, it's not possible to use it to generate [2]uint64 or
//       anything resembling a 128bit hash, even though that's exactly what
//       we need in this situation.
func KeyToHash(key interface{}) (uint64, uint64) {
	if key == nil {
		return 0, 0
	}
	switch k := key.(type) {
	case uint64:
		return k, 0
	case string:
		return MemHashString(k), xxhash.Sum64String(k)
	case []byte:
		return MemHash(k), xxhash.Sum64(k)
	case byte:
		return uint64(k), 0
	case int:
		return uint64(k), 0
	case int32:
		return uint64(k), 0
	case uint32:
		return uint64(k), 0
	case int64:
		return uint64(k), 0
	default:
		panic("Key type not supported")
	}
}

var (
	dummyCloserChan <-chan struct{}
)

// Closer holds the two things we need to close a goroutine and wait for it to
// finish: a chan to tell the goroutine to shut down, and a WaitGroup with
// which to wait for it to finish shutting down.
type Closer struct {
	waiting sync.WaitGroup

	ctx    context.Context
	cancel context.CancelFunc
}

// NewCloser constructs a new Closer, with an initial count on the WaitGroup.
func NewCloser(initial int) *Closer {
	ret := &Closer{}
	ret.ctx, ret.cancel = context.WithCancel(context.Background())
	ret.waiting.Add(initial)
	return ret
}

// AddRunning Add()'s delta to the WaitGroup.
func (lc *Closer) AddRunning(delta int) {
	lc.waiting.Add(delta)
}

// Ctx can be used to get a context, which would automatically get cancelled when Signal is called.
func (lc *Closer) Ctx() context.Context {
	if lc == nil {
		return context.Background()
	}
	return lc.ctx
}

// Signal signals the HasBeenClosed signal.
func (lc *Closer) Signal() {
	// Todo(ibrahim): Change Signal to return error on next badger breaking change.
	lc.cancel()
}

// HasBeenClosed gets signaled when Signal() is called.
func (lc *Closer) HasBeenClosed() <-chan struct{} {
	if lc == nil {
		return dummyCloserChan
	}
	return lc.ctx.Done()
}

// Done calls Done() on the WaitGroup.
func (lc *Closer) Done() {
	if lc == nil {
		return
	}
	lc.waiting.Done()
}

// Wait waits on the WaitGroup. (It waits for NewCloser's initial value, AddRunning, and Done
// calls to balance out.)
func (lc *Closer) Wait() {
	lc.waiting.Wait()
}

// SignalAndWait calls Signal(), then Wait().
func (lc *Closer) SignalAndWait() {
	lc.Signal()
	lc.Wait()
}

// ZeroOut zeroes out all the bytes in the range [start, end).
func ZeroOut(dst []byte, start, end int) {
	buf := dst[start:end]
	buf[0] = 0x00
	for i := 1; i < len(buf); i *= 2 {
		copy(buf[i:], buf[:i])
	}
}
<|endoftext|>


<commit_before>package main

//import "os"
import "fmt"
import "time"

func main() {

    t := time.Now()
    s := t.Unix()

    cycle_length := 90
    sleep_delay := 15
    cycles := 6

    fmt.Printf("Current Time: %02d:%02d\n",
        time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())

    s += int64(sleep_delay * 60)

    fmt.Printf("Sleeping Begins in 15 Minutes At: %02d:%02d\n",
        time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())

    fmt.Printf("Using %d Minute Sleep Cycles\n", cycle_length)

    for i:=1; i <= cycles; i++ {
        s += 5400
        fmt.Printf("%d Cycle(s) %.2f Hours: Wake up at %02d:%02d\n", i, float32(i)*float32(1.5), time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())
    }

}

func args() {

//    argsWithProg := os.Args
//    argsWithoutProg := os.Args[1:]

//    arg := os.Args[3]

}
<commit_msg>implemented commandline args<commit_after>package main

import "os"
import "fmt"
import "time"
import "strconv"
import "reflect"

func main() {

    t := time.Now()
    s := t.Unix()

    vals := args()

    if vals[3] == 0 {
        cycle_length := 90
        sleep_delay := 15
        cycles := 6

        if vals[0] != 0 {
            cycle_length = vals[0]
        }
        if vals[1] != 0 {
            sleep_delay = vals[1]
        }
        if vals[2] != 0 {
            cycles = vals[2]
        }

        fmt.Printf("Current Time: %02d:%02d\n",
            time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())

        s += int64(sleep_delay * 60)

        fmt.Printf("Sleeping Begins in 15 Minutes At: %02d:%02d\n",
            time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())

        fmt.Printf("Using %d Minute Sleep Cycles\n", cycle_length)

        for i:=1; i <= cycles; i++ {
            s += 5400
            fmt.Printf("%d Cycle(s) %.2f Hours: Wake up at %02d:%02d\n", i, float32(i)*float32(cycle_length/60), time.Unix(s, 0).Hour(), time.Unix(s, 0).Minute())
        }
    }

}

func args() [4]int {

    args := os.Args
    ret := [4]int{0,0,0,0}

    if len(args) > 1 {
        for i := 1; i < len(args); i+=2 {
            if args[i] == "-h" {
                help_msg()
                ret[3] = 1
            } else if args[i] == "--help" {
                help_msg()
                ret[3] = 1
            } else if args[i] == "-c" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[2] = val
                }
            } else if args[i] == "--sleep-cycles" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[2] = val
                }
            } else if args[i] == "-d" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[1] = val
                }
            } else if args[i] == "--sleep-delay" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[1] = val
                }
            } else if args[i] == "-l" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[0] = val
                }
            } else if args[i] == "--cycle-length" {
                val, _ := strconv.Atoi(args[i+1])
                if reflect.TypeOf(val).Kind() == reflect.Int {
                    ret[0] = val
                }
            }
        }
    } else { return ret }
    return ret

}

func help_msg() {

    fmt.Println("usage: zzz [-h] [-c SLEEP_CYCLES] [-d SLEEP_DELAY] [-l CYCLE_LENGTH]")
    fmt.Println(" ")
    fmt.Println("Calculates wake up times based on sleep cycles")
    fmt.Println(" ")
    fmt.Println("optional arguments:")
    fmt.Println("  -h, --help            show this help message and exit")
    fmt.Println("  -c SLEEP_CYCLES, --sleep-cycles SLEEP_CYCLES")
    fmt.Println("                        number of sleep cycles to calculate")
    fmt.Println("  -d SLEEP_DELAY, --sleep-delay SLEEP_DELAY")
    fmt.Println("                        offset in minutes used to compensate for the time")
    fmt.Println("                        taken to fall asleep")
    fmt.Println("  -l CYCLE_LENGTH, --cycle-length CYCLE_LENGTH")
    fmt.Println("                        length in minutes of a complete sleep cycle")

}
<|endoftext|>


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

package table

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
)

// GroupID identifies a group. GroupIDs form a tree, rooted at
// RootGroupID (which is also the zero GroupID).
type GroupID struct {
	*groupNode
}

// RootGroupID is the root of the GroupID tree.
var RootGroupID = GroupID{}

type groupNode struct {
	parent GroupID
	label  interface{}
}

// String returns the path to GroupID g in the form "/l1/l2/l3". If g
// is RootGroupID, it returns "/". Each level in the group is formed
// by formatting the label using fmt's "%v" verb. Note that this is
// purely diagnostic; this string may not uniquely identify g.
func (g GroupID) String() string {
	if g == RootGroupID {
		return "/"
	}
	parts := []string{}
	for p := g; p != RootGroupID; p = p.parent {
		part := fmt.Sprintf("/%v", p.label)
		parts = append(parts, part)
	}
	for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
		parts[i], parts[j] = parts[j], parts[i]
	}
	return strings.Join(parts, "")
}

// Extend returns a new GroupID that is a child of GroupID g. The
// returned GroupID will not be equal to any existing GroupID (even if
// label is not unique among g's children). The label is primarily
// diagnostic; the table package uses it only when printing tables,
// but callers may store semantic information in group labels.
func (g GroupID) Extend(label interface{}) GroupID {
	return GroupID{&groupNode{g, label}}
}

// Parent returns the parent of g. The parent of RootGroupID is
// RootGroupID.
func (g GroupID) Parent() GroupID {
	if g == RootGroupID {
		return RootGroupID
	}
	return g.parent
}

// Label returns the label of g.
func (g GroupID) Label() interface{} {
	return g.label
}

// GroupBy sub-divides all groups such that all of the rows in each
// group have equal values for all of the named columns. The relative
// order of rows with equal values for the named columns is
// maintained. Grouped-by columns become constant columns within each
// group.
func GroupBy(g Grouping, cols ...string) Grouping {
	// TODO: This would generate much less garbage if we grouped
	// all of cols in one pass.
	//
	// TODO: Construct each result column as a contiguous slice
	// and then cut that up into the groups so that it's one
	// allocation per column regardless of how many groups there
	// are.

	if len(cols) == 0 {
		return g
	}

	var out GroupingBuilder
	for _, gid := range g.Tables() {
		t := g.Table(gid)

		if cv, ok := t.Const(cols[0]); ok {
			// Grouping by a constant is trivial.
			subgid := gid.Extend(cv)
			out.Add(subgid, t)
			continue
		}

		c := t.MustColumn(cols[0])

		// Create an index on c.
		type subgroupInfo struct {
			key  interface{}
			rows []int
		}
		subgroups := []subgroupInfo{}
		keys := make(map[interface{}]int)
		seq := reflect.ValueOf(c)
		for i := 0; i < seq.Len(); i++ {
			x := seq.Index(i).Interface()
			sg, ok := keys[x]
			if !ok {
				sg = len(subgroups)
				subgroups = append(subgroups, subgroupInfo{x, []int{}})
				keys[x] = sg
			}
			subgroup := &subgroups[sg]
			subgroup.rows = append(subgroup.rows, i)
		}

		// Split this group in all columns.
		for _, subgroup := range subgroups {
			// Construct this new group.
			var subtable Builder
			for _, name := range t.Columns() {
				if name == cols[0] {
					// Promote the group-by column
					// to a constant.
					subtable.AddConst(name, subgroup.key)
					continue
				}
				if cv, ok := t.Const(name); ok {
					// Keep constants constant.
					subtable.AddConst(name, cv)
					continue
				}
				seq := t.Column(name)
				seq = generic.MultiIndex(seq, subgroup.rows)
				subtable.Add(name, seq)
			}
			subgid := gid.Extend(subgroup.key)
			out.Add(subgid, subtable.Done())
		}
	}

	return GroupBy(out.Done(), cols[1:]...)
}

// Ungroup concatenates adjacent Tables in g that share a group parent
// into a Table identified by the parent, undoing the effects of the
// most recent GroupBy operation.
func Ungroup(g Grouping) Grouping {
	groups := g.Tables()
	if len(groups) == 0 || len(groups) == 1 && groups[0] == RootGroupID {
		return g
	}

	var out GroupingBuilder
	runGid := groups[0].Parent()
	runTabs := []*Table{}
	for _, gid := range groups {
		if gid.Parent() != runGid {
			// Flush the run.
			out.Add(runGid, concatRows(runTabs...))

			runGid = gid.Parent()
			runTabs = runTabs[:0]
		}
		runTabs = append(runTabs, g.Table(gid))
	}
	// Flush the last run.
	out.Add(runGid, concatRows(runTabs...))

	return out.Done()
}

// Flatten concatenates all of the groups in g into a single Table.
// This is equivalent to repeatedly Ungrouping g.
func Flatten(g Grouping) *Table {
	groups := g.Tables()
	switch len(groups) {
	case 0:
		return new(Table)

	case 1:
		return g.Table(groups[0])
	}

	tabs := make([]*Table, len(groups))
	for i, gid := range groups {
		tabs[i] = g.Table(gid)
	}

	return concatRows(tabs...)
}

// concatRows concatenates the rows of tabs into a single Table. All
// Tables in tabs must all have the same column set.
func concatRows(tabs ...*Table) *Table {
	// TODO: Consider making this public. It would have to check
	// the columns, and we would probably also want a concatCols.

	switch len(tabs) {
	case 0:
		return new(Table)

	case 1:
		return tabs[0]
	}

	// Construct each column.
	var out Builder
	seqs := make([]generic.Slice, len(tabs))
	for _, col := range tabs[0].Columns() {
		seqs = seqs[:0]
		for _, tab := range tabs {
			seqs = append(seqs, tab.Column(col))
		}
		out.Add(col, generic.Concat(seqs...))
	}

	return out.Done()
}
<commit_msg>table: construct fewer slices in GroupBy<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package table

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
)

// GroupID identifies a group. GroupIDs form a tree, rooted at
// RootGroupID (which is also the zero GroupID).
type GroupID struct {
	*groupNode
}

// RootGroupID is the root of the GroupID tree.
var RootGroupID = GroupID{}

type groupNode struct {
	parent GroupID
	label  interface{}
}

// String returns the path to GroupID g in the form "/l1/l2/l3". If g
// is RootGroupID, it returns "/". Each level in the group is formed
// by formatting the label using fmt's "%v" verb. Note that this is
// purely diagnostic; this string may not uniquely identify g.
func (g GroupID) String() string {
	if g == RootGroupID {
		return "/"
	}
	parts := []string{}
	for p := g; p != RootGroupID; p = p.parent {
		part := fmt.Sprintf("/%v", p.label)
		parts = append(parts, part)
	}
	for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
		parts[i], parts[j] = parts[j], parts[i]
	}
	return strings.Join(parts, "")
}

// Extend returns a new GroupID that is a child of GroupID g. The
// returned GroupID will not be equal to any existing GroupID (even if
// label is not unique among g's children). The label is primarily
// diagnostic; the table package uses it only when printing tables,
// but callers may store semantic information in group labels.
func (g GroupID) Extend(label interface{}) GroupID {
	return GroupID{&groupNode{g, label}}
}

// Parent returns the parent of g. The parent of RootGroupID is
// RootGroupID.
func (g GroupID) Parent() GroupID {
	if g == RootGroupID {
		return RootGroupID
	}
	return g.parent
}

// Label returns the label of g.
func (g GroupID) Label() interface{} {
	return g.label
}

// GroupBy sub-divides all groups such that all of the rows in each
// group have equal values for all of the named columns. The relative
// order of rows with equal values for the named columns is
// maintained. Grouped-by columns become constant columns within each
// group.
func GroupBy(g Grouping, cols ...string) Grouping {
	// TODO: This would generate much less garbage if we grouped
	// all of cols in one pass.
	//
	// TODO: This constructs one slice per column per input group,
	// but it would be even better if it constructed just one
	// slice per column.

	if len(cols) == 0 {
		return g
	}

	var out GroupingBuilder
	for _, gid := range g.Tables() {
		t := g.Table(gid)

		if cv, ok := t.Const(cols[0]); ok {
			// Grouping by a constant is trivial.
			subgid := gid.Extend(cv)
			out.Add(subgid, t)
			continue
		}

		c := t.MustColumn(cols[0])

		// Create an index on c.
		type subgroupInfo struct {
			key  interface{}
			rows []int
		}
		subgroups := []subgroupInfo{}
		keys := make(map[interface{}]int)
		seq := reflect.ValueOf(c)
		for i := 0; i < seq.Len(); i++ {
			x := seq.Index(i).Interface()
			sg, ok := keys[x]
			if !ok {
				sg = len(subgroups)
				subgroups = append(subgroups, subgroupInfo{x, []int{}})
				keys[x] = sg
			}
			subgroup := &subgroups[sg]
			subgroup.rows = append(subgroup.rows, i)
		}

		// Count rows in each subgroup.
		offsets := make([]int, 1+len(subgroups))
		for i := range subgroups {
			offsets[i+1] = offsets[i] + len(subgroups[i].rows)
		}

		// Split each column.
		builders := make([]Builder, len(subgroups))
		for _, name := range t.Columns() {
			if name == cols[0] {
				// Promote the group-by column to a
				// constant.
				for i := range subgroups {
					builders[i].AddConst(name, subgroups[i].key)
				}
				continue
			}

			if cv, ok := t.Const(name); ok {
				// Keep constants constant.
				for i := range builders {
					builders[i].AddConst(name, cv)
				}
				continue
			}

			// Create a slice for all of the values.
			col := t.Column(name)
			ncol := reflect.MakeSlice(reflect.TypeOf(col), t.Len(), t.Len())

			// Shuffle each subgroup into ncol.
			for i := range subgroups {
				subcol := ncol.Slice(offsets[i], offsets[i+1]).Interface()
				generic.CopyIndex(subcol, col, subgroups[i].rows)
				builders[i].Add(name, subcol)
			}
		}

		// Add tables to output Grouping.
		for i := range builders {
			subgid := gid.Extend(subgroups[i].key)
			out.Add(subgid, builders[i].Done())
		}
	}

	return GroupBy(out.Done(), cols[1:]...)
}

// Ungroup concatenates adjacent Tables in g that share a group parent
// into a Table identified by the parent, undoing the effects of the
// most recent GroupBy operation.
func Ungroup(g Grouping) Grouping {
	groups := g.Tables()
	if len(groups) == 0 || len(groups) == 1 && groups[0] == RootGroupID {
		return g
	}

	var out GroupingBuilder
	runGid := groups[0].Parent()
	runTabs := []*Table{}
	for _, gid := range groups {
		if gid.Parent() != runGid {
			// Flush the run.
			out.Add(runGid, concatRows(runTabs...))

			runGid = gid.Parent()
			runTabs = runTabs[:0]
		}
		runTabs = append(runTabs, g.Table(gid))
	}
	// Flush the last run.
	out.Add(runGid, concatRows(runTabs...))

	return out.Done()
}

// Flatten concatenates all of the groups in g into a single Table.
// This is equivalent to repeatedly Ungrouping g.
func Flatten(g Grouping) *Table {
	groups := g.Tables()
	switch len(groups) {
	case 0:
		return new(Table)

	case 1:
		return g.Table(groups[0])
	}

	tabs := make([]*Table, len(groups))
	for i, gid := range groups {
		tabs[i] = g.Table(gid)
	}

	return concatRows(tabs...)
}

// concatRows concatenates the rows of tabs into a single Table. All
// Tables in tabs must all have the same column set.
func concatRows(tabs ...*Table) *Table {
	// TODO: Consider making this public. It would have to check
	// the columns, and we would probably also want a concatCols.

	switch len(tabs) {
	case 0:
		return new(Table)

	case 1:
		return tabs[0]
	}

	// Construct each column.
	var out Builder
	seqs := make([]generic.Slice, len(tabs))
	for _, col := range tabs[0].Columns() {
		seqs = seqs[:0]
		for _, tab := range tabs {
			seqs = append(seqs, tab.Column(col))
		}
		out.Add(col, generic.Concat(seqs...))
	}

	return out.Done()
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Manuel Gauto (github.com/twa16)
 *
 * 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 simpleauth

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/satori/go.uuid"
	"golang.org/x/crypto/bcrypt"
	"strings"
	"time"
)

type AuthProvider struct {
	Database                 *gorm.DB //Database that the auth provider uses to store user information
	SessionExpireTimeSeconds int64    //The time the sessions created by this provider should live
}

type User struct {
	gorm.Model                  //All DB fields
	Username     string         `gorm:"unique"` //The username of the user
	PasswordHash []byte         `json:"-"`      //BCrypt hash of the user's password
	FirstName    string         //First name of the user
	LastName     string         //Last name of the user
	Email        *string         `gorm:"unique"` //Email of the user
	PhoneNumber  *string         `gorm:"unique"` //Phone number of the users
	Role         string         //String that represents a user's role
	Permissions  []Permission   `gorm:"ForeignKey:AuthUserID"` //The permissions the user has
	UserMetaData []UserMetadata `gorm:"ForeignKey:AuthUserID"` //The metadata of the user
	Sessions     []Session      `gorm:"ForeignKey:AuthUserID"` //Sessions associated with this user
}

type Permission struct {
	gorm.Model `json:"-"` //DB Fields
	AuthUserID uint       //ID of the user this belongs to
	Permission string     //Permission string
}

type UserMetadata struct {
	gorm.Model `json:"-"` //DB Fields
	AuthUserID uint       //ID of the user this belongs to
	Key        string     //Key for the metadata field
	Value      string     //Value for this metadata field
}

type Session struct {
	gorm.Model          `json:"-"` //DB Fields
	AuthenticationToken string     //Session key used to authorize requests
	AuthUserID          uint       //ID of user that this token belongs to
	LastSeen            int64      //Linux time of last API Call
	Persistent          bool       //If this is set to true, the key never expires.
}

type SessionCheckResponse struct {
	AuthSession *Session //Session pointer. Set if the session exists
	IsExpired   bool     //True if the session is expired
}

//Startup This method migrates all models and does all needed one time setup for the authentication provider
func (authProvider AuthProvider) Startup() {
	authProvider.Database.AutoMigrate(&User{})
	authProvider.Database.AutoMigrate(&Permission{})
	authProvider.Database.AutoMigrate(&UserMetadata{})
	authProvider.Database.AutoMigrate(&Session{})
}

//CreateUser Persists the user in the database
func (authProvider AuthProvider) CreateUser(user User) (User, error) {
	tx := authProvider.Database.Begin()
	err := tx.Save(&user).Error
	if err != nil {
		fmt.Println(err)
		//If there is an error rollback and return error
		tx.Rollback()
		return user, err
	}
	//Commit if no error
	tx.Commit()
	return user, err
}

//UpdateUser Update a user's data. This is just a wrapper around CreateUser.
func (authProvider AuthProvider) UpdateUser(user User) (User, error) {
	return authProvider.CreateUser(user)
}

//GetUser Retrieves a user from the database by their username
func (authProvider AuthProvider) GetUser(username string) (User, error) {
	var user User
	err := authProvider.Database.Where("username = ?", username).First(&user).Error
	if err != nil {
		return user, err
	}
	authProvider.Database.Model(&user).Association("Permissions").Find(&user.Permissions)
	authProvider.Database.Model(&user).Association("UserMetaData").Find(&user.UserMetaData)
	//authProvider.Database.Model(&user).Association("Sessions").Find(&user.Sessions)
	return user, err
}

//GetUserByID Gets a user from the database by their ID
func (authProvider AuthProvider) GetUserByID(userID uint) (User, error) {
	var user User
	err := authProvider.Database.First(&user, userID).Error
	if err != nil {
		return user, err
	}
	authProvider.Database.Model(&user).Association("Permissions").Find(&user.Permissions)
	authProvider.Database.Model(&user).Association("UserMetaData").Find(&user.UserMetaData)
	authProvider.Database.Model(&user).Association("Sessions").Find(&user.Sessions)
	return user, err
}

//SetUserPassword Sets the user's password
func (authProvider AuthProvider) SetUserPassword(user User, password string) error {
	passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	user.PasswordHash = passwordHash
	_, err = authProvider.UpdateUser(user)
	return err
}

//CheckLogin This function returns the user true if the credentials correspond to a user
func (authProvider AuthProvider) CheckLogin(username string, password string) (bool, error) {
	userObject, err := authProvider.GetUser(username)
	//Check if there is an error
	if err != nil {
		return false, err
	}
	//Check if the user exists
	if userObject.Username == "" {
		return false, nil
	}
	compareResultError := bcrypt.CompareHashAndPassword(userObject.PasswordHash, []byte(password))
	return compareResultError == nil, nil
}

//GenerateSessionKey Generates a Session for a user. If 'persistent' is set to true the session will never expire.
func (authProvider AuthProvider) GenerateSessionKey(userID uint, persistent bool) (Session, error) {
	sessionKey := Session{}
	sessionKey.AuthUserID = userID
	sessionKey.Persistent = persistent
	sessionKey.AuthenticationToken = uuid.NewV4().String()
	sessionKey.LastSeen = time.Now().Unix()
	tx := authProvider.Database.Begin()
	err := tx.Create(&sessionKey).Error
	if err != nil {
		//Rollback and return error if error
		tx.Rollback()
		return sessionKey, err
	}
	//Commit if there is no error
	tx.Commit()
	return sessionKey, err
}

//CheckSessionKey Checks a session key and returns the session if it exists
func (authProvider AuthProvider) CheckSessionKey(sessionKey string) (SessionCheckResponse, error) {
	var session Session
	err := authProvider.Database.Where("authentication_token = ?", sessionKey).First(&session).Error

	curTime := time.Now().Unix()
	checkResponse := SessionCheckResponse{}
	checkResponse.AuthSession = &session
	checkResponse.IsExpired = (curTime - session.LastSeen) > authProvider.SessionExpireTimeSeconds
	return checkResponse, err
}

//UpdateSessionAccessTime Sets the last access time on a session to the current time.
func (authProvider AuthProvider) UpdateSessionAccessTime(session Session) error {
	curTime := time.Now().Unix()
	if (curTime - session.LastSeen) < authProvider.SessionExpireTimeSeconds {
		session.LastSeen = curTime
		err := authProvider.Database.Save(&session).Error
		return err
	}
	return nil
}

//CheckPermission Returns true if the user has the provided permission
func (authProvider AuthProvider) CheckPermission(userID uint, permission string) (bool, error) {
	user, err := authProvider.GetUserByID(userID)
	if err != nil {
		return false, err
	}
	return authProvider.CheckPermissionLogic(permission, user.Permissions), err

}

//CheckPermissionLogic method that contains logic used to process permission checks
func (authProvider AuthProvider) CheckPermissionLogic(permissionReq string, userPermissions []Permission) bool {
	//Split Permission Request
	permReqParts := strings.Split(permissionReq, ".")
	for _, userPerm := range userPermissions {
		userPermParts := strings.Split(userPerm.Permission, ".")
		userPermPartCount := len(userPermParts)
		for ri, permReqPart := range permReqParts {
			//Check if the requested permission is too long
			if (ri + 1) > userPermPartCount {
				break
			}
			//Check if the user permission at this section is a wildcard
			if userPermParts[ri] == "*" {
				return true
			}
			//Check if the indexed parts match
			if permReqPart != userPermParts[ri] {
				break
			}
			//If all other tests pass and this is the last piece, this permission works
			if (ri + 1) == len(permReqParts) {
				return true
			}
		}
	}
	return false
}
<commit_msg>Undo comment on session association in GetUser<commit_after>/*
 * Copyright 2017 Manuel Gauto (github.com/twa16)
 *
 * 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 simpleauth

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/satori/go.uuid"
	"golang.org/x/crypto/bcrypt"
	"strings"
	"time"
)

type AuthProvider struct {
	Database                 *gorm.DB //Database that the auth provider uses to store user information
	SessionExpireTimeSeconds int64    //The time the sessions created by this provider should live
}

type User struct {
	gorm.Model                  //All DB fields
	Username     string         `gorm:"unique"` //The username of the user
	PasswordHash []byte         `json:"-"`      //BCrypt hash of the user's password
	FirstName    string         //First name of the user
	LastName     string         //Last name of the user
	Email        *string         `gorm:"unique"` //Email of the user
	PhoneNumber  *string         `gorm:"unique"` //Phone number of the users
	Role         string         //String that represents a user's role
	Permissions  []Permission   `gorm:"ForeignKey:AuthUserID"` //The permissions the user has
	UserMetaData []UserMetadata `gorm:"ForeignKey:AuthUserID"` //The metadata of the user
	Sessions     []Session      `gorm:"ForeignKey:AuthUserID"` //Sessions associated with this user
}

type Permission struct {
	gorm.Model `json:"-"` //DB Fields
	AuthUserID uint       //ID of the user this belongs to
	Permission string     //Permission string
}

type UserMetadata struct {
	gorm.Model `json:"-"` //DB Fields
	AuthUserID uint       //ID of the user this belongs to
	Key        string     //Key for the metadata field
	Value      string     //Value for this metadata field
}

type Session struct {
	gorm.Model          `json:"-"` //DB Fields
	AuthenticationToken string     //Session key used to authorize requests
	AuthUserID          uint       //ID of user that this token belongs to
	LastSeen            int64      //Linux time of last API Call
	Persistent          bool       //If this is set to true, the key never expires.
}

type SessionCheckResponse struct {
	AuthSession *Session //Session pointer. Set if the session exists
	IsExpired   bool     //True if the session is expired
}

//Startup This method migrates all models and does all needed one time setup for the authentication provider
func (authProvider AuthProvider) Startup() {
	authProvider.Database.AutoMigrate(&User{})
	authProvider.Database.AutoMigrate(&Permission{})
	authProvider.Database.AutoMigrate(&UserMetadata{})
	authProvider.Database.AutoMigrate(&Session{})
}

//CreateUser Persists the user in the database
func (authProvider AuthProvider) CreateUser(user User) (User, error) {
	tx := authProvider.Database.Begin()
	err := tx.Save(&user).Error
	if err != nil {
		fmt.Println(err)
		//If there is an error rollback and return error
		tx.Rollback()
		return user, err
	}
	//Commit if no error
	tx.Commit()
	return user, err
}

//UpdateUser Update a user's data. This is just a wrapper around CreateUser.
func (authProvider AuthProvider) UpdateUser(user User) (User, error) {
	return authProvider.CreateUser(user)
}

//GetUser Retrieves a user from the database by their username
func (authProvider AuthProvider) GetUser(username string) (User, error) {
	var user User
	err := authProvider.Database.Where("username = ?", username).First(&user).Error
	if err != nil {
		return user, err
	}
	authProvider.Database.Model(&user).Association("Permissions").Find(&user.Permissions)
	authProvider.Database.Model(&user).Association("UserMetaData").Find(&user.UserMetaData)
	authProvider.Database.Model(&user).Association("Sessions").Find(&user.Sessions)
	return user, err
}

//GetUserByID Gets a user from the database by their ID
func (authProvider AuthProvider) GetUserByID(userID uint) (User, error) {
	var user User
	err := authProvider.Database.First(&user, userID).Error
	if err != nil {
		return user, err
	}
	authProvider.Database.Model(&user).Association("Permissions").Find(&user.Permissions)
	authProvider.Database.Model(&user).Association("UserMetaData").Find(&user.UserMetaData)
	authProvider.Database.Model(&user).Association("Sessions").Find(&user.Sessions)
	return user, err
}

//SetUserPassword Sets the user's password
func (authProvider AuthProvider) SetUserPassword(user User, password string) error {
	passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	user.PasswordHash = passwordHash
	_, err = authProvider.UpdateUser(user)
	return err
}

//CheckLogin This function returns the user true if the credentials correspond to a user
func (authProvider AuthProvider) CheckLogin(username string, password string) (bool, error) {
	userObject, err := authProvider.GetUser(username)
	//Check if there is an error
	if err != nil {
		return false, err
	}
	//Check if the user exists
	if userObject.Username == "" {
		return false, nil
	}
	compareResultError := bcrypt.CompareHashAndPassword(userObject.PasswordHash, []byte(password))
	return compareResultError == nil, nil
}

//GenerateSessionKey Generates a Session for a user. If 'persistent' is set to true the session will never expire.
func (authProvider AuthProvider) GenerateSessionKey(userID uint, persistent bool) (Session, error) {
	sessionKey := Session{}
	sessionKey.AuthUserID = userID
	sessionKey.Persistent = persistent
	sessionKey.AuthenticationToken = uuid.NewV4().String()
	sessionKey.LastSeen = time.Now().Unix()
	tx := authProvider.Database.Begin()
	err := tx.Create(&sessionKey).Error
	if err != nil {
		//Rollback and return error if error
		tx.Rollback()
		return sessionKey, err
	}
	//Commit if there is no error
	tx.Commit()
	return sessionKey, err
}

//CheckSessionKey Checks a session key and returns the session if it exists
func (authProvider AuthProvider) CheckSessionKey(sessionKey string) (SessionCheckResponse, error) {
	var session Session
	err := authProvider.Database.Where("authentication_token = ?", sessionKey).First(&session).Error

	curTime := time.Now().Unix()
	checkResponse := SessionCheckResponse{}
	checkResponse.AuthSession = &session
	checkResponse.IsExpired = (curTime - session.LastSeen) > authProvider.SessionExpireTimeSeconds
	return checkResponse, err
}

//UpdateSessionAccessTime Sets the last access time on a session to the current time.
func (authProvider AuthProvider) UpdateSessionAccessTime(session Session) error {
	curTime := time.Now().Unix()
	if (curTime - session.LastSeen) < authProvider.SessionExpireTimeSeconds {
		session.LastSeen = curTime
		err := authProvider.Database.Save(&session).Error
		return err
	}
	return nil
}

//CheckPermission Returns true if the user has the provided permission
func (authProvider AuthProvider) CheckPermission(userID uint, permission string) (bool, error) {
	user, err := authProvider.GetUserByID(userID)
	if err != nil {
		return false, err
	}
	return authProvider.CheckPermissionLogic(permission, user.Permissions), err

}

//CheckPermissionLogic method that contains logic used to process permission checks
func (authProvider AuthProvider) CheckPermissionLogic(permissionReq string, userPermissions []Permission) bool {
	//Split Permission Request
	permReqParts := strings.Split(permissionReq, ".")
	for _, userPerm := range userPermissions {
		userPermParts := strings.Split(userPerm.Permission, ".")
		userPermPartCount := len(userPermParts)
		for ri, permReqPart := range permReqParts {
			//Check if the requested permission is too long
			if (ri + 1) > userPermPartCount {
				break
			}
			//Check if the user permission at this section is a wildcard
			if userPermParts[ri] == "*" {
				return true
			}
			//Check if the indexed parts match
			if permReqPart != userPermParts[ri] {
				break
			}
			//If all other tests pass and this is the last piece, this permission works
			if (ri + 1) == len(permReqParts) {
				return true
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"crypto/subtle"
	"encoding/base64"
	"strconv"
)

const AuthUserKey = "user"

type (
	Accounts map[string]string
	authPair struct {
		Value string
		User  string
	}
	authPairs []authPair
)

func (a authPairs) searchCredential(authValue string) (string, bool) {
	if len(authValue) == 0 {
		return "", false
	}
	for _, pair := range a {
		if pair.Value == authValue {
			return pair.User, true
		}
	}
	return "", false
}

// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
// the key is the user name and the value is the password, as well as the name of the Realm.
// If the realm is empty, "Authorization Required" will be used by default.
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
	if realm == "" {
		realm = "Authorization Required"
	}
	realm = "Basic realm=" + strconv.Quote(realm)
	pairs := processAccounts(accounts)
	return func(c *Context) {
		// Search user in the slice of allowed credentials
		user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
		if !found {
			// Credentials doesn't match, we return 401 and abort handlers chain.
			c.Header("WWW-Authenticate", realm)
			c.AbortWithStatus(401)
		} else {
			// The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using
			// c.MustGet(gin.AuthUserKey)
			c.Set(AuthUserKey, user)
		}
	}
}

// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
// the key is the user name and the value is the password.
func BasicAuth(accounts Accounts) HandlerFunc {
	return BasicAuthForRealm(accounts, "")
}

func processAccounts(accounts Accounts) authPairs {
	assert1(len(accounts) > 0, "Empty list of authorized credentials")
	pairs := make(authPairs, 0, len(accounts))
	for user, password := range accounts {
		assert1(len(user) > 0, "User can not be empty")
		value := authorizationHeader(user, password)
		pairs = append(pairs, authPair{
			Value: value,
			User:  user,
		})
	}
	return pairs
}

func authorizationHeader(user, password string) string {
	base := user + ":" + password
	return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
}

func secureCompare(given, actual string) bool {
	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
		return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
	}
	/* Securely compare actual to itself to keep constant time, but always return false */
	return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
}
<commit_msg>docs(auth): add missing logs for auth.go<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"crypto/subtle"
	"encoding/base64"
	"strconv"
)

// AuthUserKey is the cookie name for user credential in basic auth
const AuthUserKey = "user"

type (
	// Accounts defines a key/value for user/pass list of authorized logins
	Accounts map[string]string
	authPair struct {
		Value string
		User  string
	}
	authPairs []authPair
)

func (a authPairs) searchCredential(authValue string) (string, bool) {
	if len(authValue) == 0 {
		return "", false
	}
	for _, pair := range a {
		if pair.Value == authValue {
			return pair.User, true
		}
	}
	return "", false
}

// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
// the key is the user name and the value is the password, as well as the name of the Realm.
// If the realm is empty, "Authorization Required" will be used by default.
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
	if realm == "" {
		realm = "Authorization Required"
	}
	realm = "Basic realm=" + strconv.Quote(realm)
	pairs := processAccounts(accounts)
	return func(c *Context) {
		// Search user in the slice of allowed credentials
		user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
		if !found {
			// Credentials doesn't match, we return 401 and abort handlers chain.
			c.Header("WWW-Authenticate", realm)
			c.AbortWithStatus(401)
		} else {
			// The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using
			// c.MustGet(gin.AuthUserKey)
			c.Set(AuthUserKey, user)
		}
	}
}

// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
// the key is the user name and the value is the password.
func BasicAuth(accounts Accounts) HandlerFunc {
	return BasicAuthForRealm(accounts, "")
}

func processAccounts(accounts Accounts) authPairs {
	assert1(len(accounts) > 0, "Empty list of authorized credentials")
	pairs := make(authPairs, 0, len(accounts))
	for user, password := range accounts {
		assert1(len(user) > 0, "User can not be empty")
		value := authorizationHeader(user, password)
		pairs = append(pairs, authPair{
			Value: value,
			User:  user,
		})
	}
	return pairs
}

func authorizationHeader(user, password string) string {
	base := user + ":" + password
	return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
}

func secureCompare(given, actual string) bool {
	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
		return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
	}
	/* Securely compare actual to itself to keep constant time, but always return false */
	return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/gob"
	"errors"
	"time"

	"golang.org/x/crypto/bcrypt"

	"github.com/gin-contrib/sessions"
	db "upper.io/db.v3"
	"upper.io/db.v3/lib/sqlbuilder"
)

const (
	// USER as global key identifier when storing data into session
	USER = "user"
)

const (
	// StatusInactive represent user with inactive status
	StatusInactive = false
	// StatusActive represent user with active status
	StatusActive = true
	// StatusNotPremium represent user with not premium status
	StatusNotPremium = false
	// StatusPremium represent user with premium status
	StatusPremium = true
)

var (
	// ErrMissmatch displaying error message when user failed to be authenticated
	ErrMissmatch = errors.New("missmatch username / password combination")
	// ErrUserDuplicate displaying error message when the same user has been registered
	ErrUserDuplicate = errors.New("user duplicate")
	// ErrNotFound displaying error message when user has not been found
	ErrNotFound = errors.New("user not found")
	// ErrInactive displaying error message when user has inactive status
	ErrInactive = errors.New("inactive user")
)

// UserModel data
type UserModel interface {
	SetIsActive(bool)
	SetCreatedTime(time.Time)
	GetID() uint64
	GetFirstName() *string
	GetLastName() *string
	GetUsername() string
	GetPassword() []byte
	GetIsActive() bool
	TableName() string
}

// Module for Authentication
type Module struct {
	db      sqlbuilder.Database
	session sessions.Session
}

// User data to store in session
type User struct {
	UserID              uint64
	Username            string
	FirstName, LastName *string
}

func init() {
	gob.Register(User{})
}

// New create new Authentication Module
func New(db sqlbuilder.Database) Module {
	return Module{db: db}
}

// UpdateSession replacing current sessions.Session in the module
func (mod *Module) UpdateSession(sess sessions.Session) {
	mod.session = sess
}

// CreateNewUser storing new user data into repository
func (mod *Module) CreateNewUser(data UserModel) (UserModel, error) {
	// check username exist
	if total, _ := mod.db.Collection(data.TableName()).
		Find(db.Cond{"username": data.GetUsername()}).Count(); total != 0 {
		return data, ErrUserDuplicate
	}
	// making sure user is not active and not premium
	data.SetIsActive(StatusInactive)
	data.SetCreatedTime(time.Now().UTC())
	// storing data
	if _, err := mod.db.Collection(data.TableName()).
		Insert(&data); err != nil {
		return data, err
	}
	return data, nil
}

// Authenticate verify username and password is match with bcrypt Encryption
func (mod *Module) Authenticate(data UserModel, password string) (UserModel, error) {
	// check username exist and active
	if err := mod.db.Collection(data.TableName()).
		Find(db.Cond{"username": data.GetUsername(), "deleted_at": nil}).
		One(&data); err != nil {
		if err == db.ErrNoMoreRows {
			return data, ErrNotFound
		}
		return data, err
	}
	if !data.GetIsActive() {
		return data, ErrInactive
	}
	// compare []byte(password) and []byte(user.Password) data
	if err := bcrypt.CompareHashAndPassword(data.GetPassword(), []byte(password)); err != nil {
		return data, ErrMissmatch
	}
	// storing into session
	mod.session.Set(USER, User{
		UserID:    data.GetID(),
		Username:  data.GetUsername(),
		FirstName: data.GetFirstName(),
		LastName:  data.GetLastName(),
	})
	err := mod.session.Save()
	return data, err
}

// Deauthenticate delete user from current session
func (mod *Module) Deauthenticate() error {
	mod.session.Delete(USER)
	return mod.session.Save()
}

// IsAuthenticated helper to check whether current session
// has been authenticated or not
func (mod *Module) IsAuthenticated() bool {
	model, err := mod.User()
	if err != nil {
		return false
	}
	return model.UserID != 0
}

// User returning user data from session
func (mod *Module) User() (User, error) {
	var (
		ok    bool
		model User
	)
	if model, ok = mod.session.Get(USER).(User); !ok {
		return model, errors.New("user not found")
	}
	return model, nil
}
<commit_msg>remove premium<commit_after>package auth

import (
	"encoding/gob"
	"errors"
	"time"

	"golang.org/x/crypto/bcrypt"

	"github.com/gin-contrib/sessions"
	db "upper.io/db.v3"
	"upper.io/db.v3/lib/sqlbuilder"
)

const (
	// USER as global key identifier when storing data into session
	USER = "user"
)

const (
	// StatusInactive represent user with inactive status
	StatusInactive = false
	// StatusActive represent user with active status
	StatusActive = true
)

var (
	// ErrMissmatch displaying error message when user failed to be authenticated
	ErrMissmatch = errors.New("missmatch username / password combination")
	// ErrUserDuplicate displaying error message when the same user has been registered
	ErrUserDuplicate = errors.New("user duplicate")
	// ErrNotFound displaying error message when user has not been found
	ErrNotFound = errors.New("user not found")
	// ErrInactive displaying error message when user has inactive status
	ErrInactive = errors.New("inactive user")
)

// UserModel data
type UserModel interface {
	SetIsActive(bool)
	SetCreatedTime(time.Time)
	GetID() uint64
	GetFirstName() *string
	GetLastName() *string
	GetUsername() string
	GetPassword() []byte
	GetIsActive() bool
	TableName() string
}

// Module for Authentication
type Module struct {
	db      sqlbuilder.Database
	session sessions.Session
}

// User data to store in session
type User struct {
	UserID              uint64
	Username            string
	FirstName, LastName *string
}

func init() {
	gob.Register(User{})
}

// New create new Authentication Module
func New(db sqlbuilder.Database) Module {
	return Module{db: db}
}

// UpdateSession replacing current sessions.Session in the module
func (mod *Module) UpdateSession(sess sessions.Session) {
	mod.session = sess
}

// CreateNewUser storing new user data into repository
func (mod *Module) CreateNewUser(data UserModel) (UserModel, error) {
	// check username exist
	if total, _ := mod.db.Collection(data.TableName()).
		Find(db.Cond{"username": data.GetUsername()}).Count(); total != 0 {
		return data, ErrUserDuplicate
	}
	// making sure user is not active and created time is utc.now
	data.SetIsActive(StatusInactive)
	data.SetCreatedTime(time.Now().UTC())
	// storing data
	if _, err := mod.db.Collection(data.TableName()).
		Insert(&data); err != nil {
		return data, err
	}
	return data, nil
}

// Authenticate verify username and password is match with bcrypt Encryption
func (mod *Module) Authenticate(data UserModel, password string) (UserModel, error) {
	// check username exist and active
	if err := mod.db.Collection(data.TableName()).
		Find(db.Cond{"username": data.GetUsername(), "deleted_at": nil}).
		One(&data); err != nil {
		if err == db.ErrNoMoreRows {
			return data, ErrNotFound
		}
		return data, err
	}
	if !data.GetIsActive() {
		return data, ErrInactive
	}
	// compare []byte(password) and []byte(user.Password) data
	if err := bcrypt.CompareHashAndPassword(data.GetPassword(), []byte(password)); err != nil {
		return data, ErrMissmatch
	}
	// storing into session
	mod.session.Set(USER, User{
		UserID:    data.GetID(),
		Username:  data.GetUsername(),
		FirstName: data.GetFirstName(),
		LastName:  data.GetLastName(),
	})
	err := mod.session.Save()
	return data, err
}

// Deauthenticate delete user from current session
func (mod *Module) Deauthenticate() error {
	mod.session.Delete(USER)
	return mod.session.Save()
}

// IsAuthenticated helper to check whether current session
// has been authenticated or not
func (mod *Module) IsAuthenticated() bool {
	model, err := mod.User()
	if err != nil {
		return false
	}
	return model.UserID != 0
}

// User returning user data from session
func (mod *Module) User() (User, error) {
	var (
		ok    bool
		model User
	)
	if model, ok = mod.session.Get(USER).(User); !ok {
		return model, errors.New("user not found")
	}
	return model, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os/exec"
	"os"
	"path"
)

var cmdUseDXAuth = &Command{
	Run:   runUseDXAuth,
	Usage: "usedxauth [dx-username or alias]",
	Short: "Authenticate with SFDX Scratch Org User",
	Long: `
Authenticate with SFDX Scratch Org User. If a user or alias is passed to the command then an attempt is made to find that user authentication info.  If no user or alias is passed an attempt is made to find the default user based on sfdx config.

Examples:

  force usedxauth test-d1df0gyckgpr@dcarroll_company.net
  force usedxauth ScratchUserAlias
  force usedxauth
`,
}

type UserAuth struct {
	AccessToken string
	Alias       string
	ClientId    string
	CreatedBy   string
	DevHubId    string
	Edition     string
	Id          string
	InstanceUrl string
	OrgName     string
	Password    string
	Status      string
	Username    string
}

func init() {
}

func runUseDXAuth(cmd *Command, args []string) {
	var auth map[string]interface{}
	var err error
	if len(args) == 0 {
		fmt.Println("Determining default user...")
		auth, _ = getDefaultItem()
	} else {
		user := args[0]
		fmt.Printf("Looking for %s in DX orgs...\n", user)
		auth, err = getOrgListItem(user)
		if err != nil {
			ErrorAndExit(err.Error())
		}
	}

	connStatus := fmt.Sprintf("%s", auth["connectedStatus"])
	username := fmt.Sprintf("%s", auth["username"])
	alias := fmt.Sprintf("%s", auth["alias"])
	if connStatus == "Connected" || connStatus == "Unknown" {
		authData := getSFDXAuth(username)
		authData.Alias = alias
		authData.Username = username
		setActiveCreds(authData)
		if len(authData.Alias) > 0 {
			fmt.Printf("Now using DX credentials for %s (%s)\n", username, alias)
		} else {
			fmt.Printf("Now using DX credentials for %s\n", username)
		}
	} else {
		ErrorAndExit("Could not determine connection status for %s", username)
	}
}

func setActiveCreds(authData UserAuth) {
	creds := ForceCredentials{}
	creds.AccessToken = authData.AccessToken
	creds.InstanceUrl = authData.InstanceUrl
	creds.IsCustomEP = true
	creds.ApiVersion = "40.0"
	creds.ForceEndpoint = 4
	creds.IsHourly = false
	creds.HourlyCheck = false

	body, err := json.Marshal(creds)
	if err != nil {
		ErrorAndExit(err.Error())
	}

	configName := authData.Alias
	if len(configName) == 0 {
		configName = authData.Username
	}

	Config.Save("accounts", configName, string(body))
	Config.Save("current", "account", configName)
}

func getDefaultItem()(data map[string]interface{}, err error) {
	md, err := getOrgList()
	defUsers, err := findDefaultUserInOrgList(md)

	if len(defUsers) == 0 {
		ErrorAndExit("No default user logins found")
	}

	if len(defUsers) == 1 {
		data = defUsers[0]
	} else {
		var hubUser map[string]interface{}
		var scrUser map[string]interface{}
		for _, y := range defUsers {
			if y["defaultMarker"] == "(D)" {
				hubUser = y
			} else {
				scrUser = y
			}
		}
		if inProjectDir() == true {
			data = scrUser
		} else {
			data = hubUser
		}
	}
	if len(fmt.Sprintf("%s", data["alias"])) > 0 {
		fmt.Printf("Getting auth for %s (%s)...\n", data["username"], data["alias"])
	} else {
		fmt.Printf("Getting auth for %s\n...", data["username"])
	}
	return
}

func inProjectDir()(bool) {
	dir, err := os.Getwd()
	_, err = os.Stat(path.Join(dir, ".sfdx"))

	return err == nil
}

func getOrgListItem(user string)(data map[string]interface{}, err error) {
	md, err := getOrgList()
	data, err = findUserInOrgList(user, md)
	return
}

func getOrgList() (data map[string]interface{}, err error) {
	cmd := exec.Command("sfdx", "force:org:list", "--json")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}
	type Orgs struct {
		NonScratchOrgs map[string]interface{}
		ScratchOrgs    map[string]interface{}
	}

	if err := json.NewDecoder(stdout).Decode(&data); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}

	return
}

func findUserInOrgList(user string, md map[string]interface{})(data map[string]interface{}, err error) {
	for k, v := range md {
		fmt.Println(v)
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["username"] == user || auth["alias"] == user {
						if len(fmt.Sprintf("%s", auth["alias"])) > 0 {
							fmt.Printf("Getting auth for %s (%s)...\n", auth["username"], auth["alias"])
						} else {
							fmt.Printf("Getting auth for %s\n...", auth["username"])
						}
						data = auth
						err = nil
						return
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	err = fmt.Errorf("Could not find and alias or username that matches %s", user)
	return
}

func findDefaultUserInOrgList(md map[string]interface{})(data []map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["isDefaultUsername"] == true || auth["isDefaultDevHubUsername"] == true {
						// Add auth to slice
						data = append(data, auth)
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	if len(data) == 0 {
		err = fmt.Errorf("Could not find a default user")
	}
	return
}

func getSFDXAuth(user string) (auth UserAuth) {
	cmd := exec.Command("sfdx", "force:org:display", "-u"+user, "--json")

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}

	type authData struct {
		Result UserAuth
	}
	var aData authData
	if err := json.NewDecoder(stdout).Decode(&aData); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}
	return aData.Result
}
<commit_msg>go fat<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path"
)

var cmdUseDXAuth = &Command{
	Run:   runUseDXAuth,
	Usage: "usedxauth [dx-username or alias]",
	Short: "Authenticate with SFDX Scratch Org User",
	Long: `
Authenticate with SFDX Scratch Org User. If a user or alias is passed to the command then an attempt is made to find that user authentication info.  If no user or alias is passed an attempt is made to find the default user based on sfdx config.

Examples:

  force usedxauth test-d1df0gyckgpr@dcarroll_company.net
  force usedxauth ScratchUserAlias
  force usedxauth
`,
}

type UserAuth struct {
	AccessToken string
	Alias       string
	ClientId    string
	CreatedBy   string
	DevHubId    string
	Edition     string
	Id          string
	InstanceUrl string
	OrgName     string
	Password    string
	Status      string
	Username    string
}

func init() {
}

func runUseDXAuth(cmd *Command, args []string) {
	var auth map[string]interface{}
	var err error
	if len(args) == 0 {
		fmt.Println("Determining default user...")
		auth, _ = getDefaultItem()
	} else {
		user := args[0]
		fmt.Printf("Looking for %s in DX orgs...\n", user)
		auth, err = getOrgListItem(user)
		if err != nil {
			ErrorAndExit(err.Error())
		}
	}

	connStatus := fmt.Sprintf("%s", auth["connectedStatus"])
	username := fmt.Sprintf("%s", auth["username"])
	alias := fmt.Sprintf("%s", auth["alias"])
	if connStatus == "Connected" || connStatus == "Unknown" {
		authData := getSFDXAuth(username)
		authData.Alias = alias
		authData.Username = username
		setActiveCreds(authData)
		if len(authData.Alias) > 0 {
			fmt.Printf("Now using DX credentials for %s (%s)\n", username, alias)
		} else {
			fmt.Printf("Now using DX credentials for %s\n", username)
		}
	} else {
		ErrorAndExit("Could not determine connection status for %s", username)
	}
}

func setActiveCreds(authData UserAuth) {
	creds := ForceCredentials{}
	creds.AccessToken = authData.AccessToken
	creds.InstanceUrl = authData.InstanceUrl
	creds.IsCustomEP = true
	creds.ApiVersion = "40.0"
	creds.ForceEndpoint = 4
	creds.IsHourly = false
	creds.HourlyCheck = false

	body, err := json.Marshal(creds)
	if err != nil {
		ErrorAndExit(err.Error())
	}

	configName := authData.Alias
	if len(configName) == 0 {
		configName = authData.Username
	}

	Config.Save("accounts", configName, string(body))
	Config.Save("current", "account", configName)
}

func getDefaultItem() (data map[string]interface{}, err error) {
	md, err := getOrgList()
	defUsers, err := findDefaultUserInOrgList(md)

	if len(defUsers) == 0 {
		ErrorAndExit("No default user logins found")
	}

	if len(defUsers) == 1 {
		data = defUsers[0]
	} else {
		var hubUser map[string]interface{}
		var scrUser map[string]interface{}
		for _, y := range defUsers {
			if y["defaultMarker"] == "(D)" {
				hubUser = y
			} else {
				scrUser = y
			}
		}
		if inProjectDir() == true {
			data = scrUser
		} else {
			data = hubUser
		}
	}
	if len(fmt.Sprintf("%s", data["alias"])) > 0 {
		fmt.Printf("Getting auth for %s (%s)...\n", data["username"], data["alias"])
	} else {
		fmt.Printf("Getting auth for %s\n...", data["username"])
	}
	return
}

func inProjectDir() bool {
	dir, err := os.Getwd()
	_, err = os.Stat(path.Join(dir, ".sfdx"))

	return err == nil
}

func getOrgListItem(user string) (data map[string]interface{}, err error) {
	md, err := getOrgList()
	data, err = findUserInOrgList(user, md)
	return
}

func getOrgList() (data map[string]interface{}, err error) {
	cmd := exec.Command("sfdx", "force:org:list", "--json")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}
	type Orgs struct {
		NonScratchOrgs map[string]interface{}
		ScratchOrgs    map[string]interface{}
	}

	if err := json.NewDecoder(stdout).Decode(&data); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}

	return
}

func findUserInOrgList(user string, md map[string]interface{}) (data map[string]interface{}, err error) {
	for k, v := range md {
		fmt.Println(v)
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["username"] == user || auth["alias"] == user {
						if len(fmt.Sprintf("%s", auth["alias"])) > 0 {
							fmt.Printf("Getting auth for %s (%s)...\n", auth["username"], auth["alias"])
						} else {
							fmt.Printf("Getting auth for %s\n...", auth["username"])
						}
						data = auth
						err = nil
						return
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	err = fmt.Errorf("Could not find and alias or username that matches %s", user)
	return
}

func findDefaultUserInOrgList(md map[string]interface{}) (data []map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["isDefaultUsername"] == true || auth["isDefaultDevHubUsername"] == true {
						// Add auth to slice
						data = append(data, auth)
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	if len(data) == 0 {
		err = fmt.Errorf("Could not find a default user")
	}
	return
}

func getSFDXAuth(user string) (auth UserAuth) {
	cmd := exec.Command("sfdx", "force:org:display", "-u"+user, "--json")

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}

	type authData struct {
		Result UserAuth
	}
	var aData authData
	if err := json.NewDecoder(stdout).Decode(&aData); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}
	return aData.Result
}
<|endoftext|>