<commit_before>package client

import (
	"context"
	"fmt"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
)

type CmdChatListChannels struct {
	libkb.Contextified

	tlfName   string
	topicType chat1.TopicType
}

func NewCmdChatListChannelsRunner(g *libkb.GlobalContext) *CmdChatListChannels {
	return &CmdChatListChannels{
		Contextified: libkb.NewContextified(g),
	}
}

func newCmdChatListChannels(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "list-channels",
		Usage:        "List on channels on a team",
		ArgumentHelp: "<team name>",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdChatListChannelsRunner(g), "list-channels", c)
		},
		Flags: mustGetChatFlags("topic-type"),
	}
}

func (c *CmdChatListChannels) Run() error {
	ui := c.G().UI.GetTerminalUI()
	chatClient, err := GetChatLocalClient(c.G())
	if err != nil {
		return err
	}

	ctx := context.Background()
	listRes, err := chatClient.GetTLFConversationsLocal(ctx, chat1.GetTLFConversationsLocalArg{
		TlfName:     c.tlfName,
		TopicType:   c.topicType,
		MembersType: chat1.ConversationMembersType_TEAM,
	})
	if err != nil {
		return err
	}

	ui.Printf("Listing channels on %s:\n\n", c.tlfName)
	for _, c := range listRes.Convs {
		convLine := fmt.Sprintf("#%s", c.Channel)
		if c.Headline != "" {
			convLine += fmt.Sprintf(" [%s]", c.Headline)
		}
		if c.CreatorInfo != nil {
			convLine += fmt.Sprintf(" (created by: %s on: %s)", c.CreatorInfo.Username,
				c.CreatorInfo.Ctime.Time().Format("2006-01-02"))
		}
		ui.Printf(convLine + "\n")
	}

	return nil
}

func (c *CmdChatListChannels) ParseArgv(ctx *cli.Context) (err error) {
	if len(ctx.Args()) != 1 {
		cli.ShowCommandHelp(ctx, "list-channels")
		return fmt.Errorf("incorrect usage")
	}

	c.tlfName = ctx.Args().Get(0)
	if c.topicType, err = parseConversationTopicType(ctx); err != nil {
		return err
	}
	return nil
}

func (c *CmdChatListChannels) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<commit_msg>Fix typo (#9024)<commit_after>package client

import (
	"context"
	"fmt"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
)

type CmdChatListChannels struct {
	libkb.Contextified

	tlfName   string
	topicType chat1.TopicType
}

func NewCmdChatListChannelsRunner(g *libkb.GlobalContext) *CmdChatListChannels {
	return &CmdChatListChannels{
		Contextified: libkb.NewContextified(g),
	}
}

func newCmdChatListChannels(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "list-channels",
		Usage:        "List of channels on a team",
		ArgumentHelp: "<team name>",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdChatListChannelsRunner(g), "list-channels", c)
		},
		Flags: mustGetChatFlags("topic-type"),
	}
}

func (c *CmdChatListChannels) Run() error {
	ui := c.G().UI.GetTerminalUI()
	chatClient, err := GetChatLocalClient(c.G())
	if err != nil {
		return err
	}

	ctx := context.Background()
	listRes, err := chatClient.GetTLFConversationsLocal(ctx, chat1.GetTLFConversationsLocalArg{
		TlfName:     c.tlfName,
		TopicType:   c.topicType,
		MembersType: chat1.ConversationMembersType_TEAM,
	})
	if err != nil {
		return err
	}

	ui.Printf("Listing channels on %s:\n\n", c.tlfName)
	for _, c := range listRes.Convs {
		convLine := fmt.Sprintf("#%s", c.Channel)
		if c.Headline != "" {
			convLine += fmt.Sprintf(" [%s]", c.Headline)
		}
		if c.CreatorInfo != nil {
			convLine += fmt.Sprintf(" (created by: %s on: %s)", c.CreatorInfo.Username,
				c.CreatorInfo.Ctime.Time().Format("2006-01-02"))
		}
		ui.Printf(convLine + "\n")
	}

	return nil
}

func (c *CmdChatListChannels) ParseArgv(ctx *cli.Context) (err error) {
	if len(ctx.Args()) != 1 {
		cli.ShowCommandHelp(ctx, "list-channels")
		return fmt.Errorf("incorrect usage")
	}

	c.tlfName = ctx.Args().Get(0)
	if c.topicType, err = parseConversationTopicType(ctx); err != nil {
		return err
	}
	return nil
}

func (c *CmdChatListChannels) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"socialapi/request"
	"strings"

	"github.com/koding/bongo"
)

type Account struct {
	// unique id of the account
	Id int64 `json:"id,string"`

	// old id of the account, which is originally
	// perisisted in mongo
	// mongo ids has 24 char
	OldId string `json:"oldId"      sql:"NOT NULL;UNIQUE;TYPE:VARCHAR(24);"`

	// IsTroll
	IsTroll bool `json:"isTroll"`

	// unique account nicknames
	Nick string `json:"nick"        sql:"NOT NULL;UNIQUE;TYPE:VARCHAR(25);"`

	// ShareLocation is a setting for users for sharing their location on socialapi
	ShareLocation bool `json:"shareLocation"`

	// unique account tokens used for pubnub authentication
	Token string `json:"-"`
}

func ValidateAccount(a *Account) error {
	if a.OldId == "" {
		return ErrOldIdIsNotSet
	}

	if strings.Contains(a.Nick, "guest-") {
		return ErrGuestsAreNotAllowed
	}
	return nil
}

// Tests are done.
func (a *Account) FetchOrCreate() error {
	if err := ValidateAccount(a); err != nil {
		return err
	}

	selector := map[string]interface{}{
		"old_id": a.OldId,
	}

	err := a.One(bongo.NewQS(selector))
	// if we dont get any error
	// it means we found the record in our db
	if err == nil {
		return nil
	}

	// first check if the err is not found err
	if err == bongo.RecordNotFound {
		if a.Nick == "" {
			return ErrNickIsNotSet
		}

		if err := a.Create(); err != nil {
			return err
		}

		return nil
	}

	return err
}

func (a *Account) FetchChannels(q *request.Query) ([]Channel, error) {
	cp := NewChannelParticipant()
	// fetch channel ids
	cids, err := cp.FetchParticipatedChannelIds(a, q)
	if err != nil {
		return nil, err
	}

	// fetch channels by their ids
	channels, err := NewChannel().FetchByIds(cids)
	if err != nil {
		return nil, err
	}

	return channels, nil
}

// TO-DO
// Control functions and remove ?
func (a *Account) Follow(targetId int64) (*ChannelParticipant, error) {
	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err == nil {
		return c.AddParticipant(targetId)
	}

	if err == bongo.RecordNotFound {
		c, err := a.CreateFollowingFeedChannel()
		if err != nil {
			return nil, err
		}
		return c.AddParticipant(targetId)
	}

	return nil, err
}

// TO-DO
// Control functions and remove ?
func (a *Account) Unfollow(targetId int64) (*Account, error) {
	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err != nil {
		return nil, err
	}

	return a, c.RemoveParticipant(targetId)
}

func (a *Account) FetchFollowerIds(q *request.Query) ([]int64, error) {
	followerIds := make([]int64, 0)
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err != nil {
		return followerIds, err
	}

	participants, err := c.FetchParticipantIds(q)
	if err != nil {
		return followerIds, err
	}

	return participants, nil
}

// FetchChannel fetchs the channel of the account
//
// Channel_TYPE_GROUP as parameter returns error , in the tests!!!!
// TO-DO, other types dont return error
//
// Tests are done
func (a *Account) FetchChannel(channelType string) (*Channel, error) {
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c := NewChannel()
	selector := map[string]interface{}{
		"creator_id":    a.Id,
		"type_constant": channelType,
	}

	if err := c.One(bongo.NewQS(selector)); err != nil {
		return nil, err
	}

	return c, nil
}

// Tests are done.
func (a *Account) ByNick(nick string) error {
	if nick == "" {
		return ErrNickIsNotSet
	}

	selector := map[string]interface{}{
		"nick": nick,
	}

	return a.One(bongo.NewQS(selector))
}

// Tests are done.
func (a *Account) MarkAsTroll() error {
	if a.Id == 0 {
		return ErrAccountIdIsNotSet
	}

	if err := a.ById(a.Id); err != nil {
		return err
	}

	// once, mongo sync problem happened and we couldnt mark the user as troll
	// in social api, in order to prevent it from happening again, i am removing
	// this check ~ CS

	// // do not try to mark twice
	// if a.IsTroll {
	// 	return fmt.Errorf("account is already a troll %d", a.Id)
	// }

	a.IsTroll = true
	if err := a.Update(); err != nil {
		return err
	}

	if err := bongo.B.PublishEvent("marked_as_troll", a); err != nil {
		return err
	}

	return nil
}

// Tests are done
func (a *Account) UnMarkAsTroll() error {
	if a.Id == 0 {
		return ErrAccountIdIsNotSet
	}

	if err := a.ById(a.Id); err != nil {
		return err
	}

	// once, mongo sync problem happened and we couldnt mark the user as troll
	// in social api, in order to prevent it from happening again, i am removing
	// this check ~ CS

	// // do not try to un-mark twice
	// if !a.IsTroll {
	// 	return fmt.Errorf("account is not a troll %d", a.Id)
	// }

	a.IsTroll = false
	if err := a.Update(); err != nil {
		return err
	}

	if err := bongo.B.PublishEvent("unmarked_as_troll", a); err != nil {
		return err
	}

	return nil
}

// Tests are done.
func (a *Account) CreateFollowingFeedChannel() (*Channel, error) {
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c := NewChannel()
	c.CreatorId = a.Id
	c.Name = fmt.Sprintf("%d-FollowingFeedChannel", a.Id)
	c.GroupName = Channel_KODING_NAME
	c.Purpose = "Following Feed for Me"
	c.TypeConstant = Channel_TYPE_FOLLOWERS
	if err := c.Create(); err != nil {
		return nil, err
	}

	return c, nil
}

func (a *Account) FetchFollowerChannelIds(q *request.Query) ([]int64, error) {

	followerIds, err := a.FetchFollowerIds(q)
	if err != nil {
		return nil, err
	}

	cp := NewChannelParticipant()
	var channelIds []int64
	res := bongo.B.DB.
		Table(cp.BongoName()).
		Where(
		"creator_id IN (?) and type_constant = ?",
		followerIds,
		Channel_TYPE_FOLLOWINGFEED,
	).Find(&channelIds)

	if err := bongo.CheckErr(res); err != nil {
		return nil, err
	}

	return channelIds, nil
}

// FetchAccountById gives all information about account by id of account
//
// Tests are done.
func FetchAccountById(accountId int64) (*Account, error) {
	a := NewAccount()
	if err := a.ById(accountId); err != nil {
		return nil, err
	}

	return a, nil
}

// FetchOldIdsByAccountIds takes slice as parameter
//
// Tests are done
func FetchOldIdsByAccountIds(accountIds []int64) ([]string, error) {
	oldIds := make([]string, 0)

	if len(accountIds) == 0 {
		return oldIds, nil
	}

	var accounts []Account
	account := Account{}

	err := bongo.B.FetchByIds(account, &accounts, accountIds)
	if err != nil {
		return oldIds, nil
	}

	for _, account := range accounts {
		// The append built-in function appends elements to the end of a slice
		oldIds = append(oldIds, account.OldId)
	}

	return oldIds, nil
}

func FetchAccountsByNicks(nicks []string) ([]Account, error) {
	var accounts []Account

	if len(nicks) == 0 {
		return accounts, nil
	}

	a := NewAccount()
	res := bongo.B.DB.
		Table(a.BongoName()).
		Where("nick in (?)", nicks).Find(&accounts)

	if err := bongo.CheckErr(res); err != nil {
		return nil, err
	}

	return accounts, nil
}
<commit_msg>socialapi: ShareLocation field is changed as Settings<commit_after>package models

import (
	"fmt"
	"socialapi/request"
	"strings"
	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type AccountSettings gorm.Hstore

func (a *AccountSettings) IsShareLocationEnabled() bool {
    if a == nil {
    return false
    }
    shareLocation, ok := gorm.Hstore(*a)["shareLocation"]
    if !ok {
        return false
        }

        if shareLocation == nil {
            return false
            }

            return *shareLocation == "true"
}

type Account struct {
	// unique id of the account
	Id int64 `json:"id,string"`

	// old id of the account, which is originally
	// perisisted in mongo
	// mongo ids has 24 char
	OldId string `json:"oldId"      sql:"NOT NULL;UNIQUE;TYPE:VARCHAR(24);"`

	// IsTroll
	IsTroll bool `json:"isTroll"`

	// unique account nicknames
	Nick string `json:"nick"        sql:"NOT NULL;UNIQUE;TYPE:VARCHAR(25);"`

	// ShareLocation is a setting for users on socialapi
	Settings gorm.Hstore `json:"settings"`

	// unique account tokens used for pubnub authentication
	Token string `json:"-"`
}

func ValidateAccount(a *Account) error {
	if a.OldId == "" {
		return ErrOldIdIsNotSet
	}

	if strings.Contains(a.Nick, "guest-") {
		return ErrGuestsAreNotAllowed
	}
	return nil
}

// Tests are done.
func (a *Account) FetchOrCreate() error {
	if err := ValidateAccount(a); err != nil {
		return err
	}

	selector := map[string]interface{}{
		"old_id": a.OldId,
	}

	err := a.One(bongo.NewQS(selector))
	// if we dont get any error
	// it means we found the record in our db
	if err == nil {
		return nil
	}

	// first check if the err is not found err
	if err == bongo.RecordNotFound {
		if a.Nick == "" {
			return ErrNickIsNotSet
		}

		if err := a.Create(); err != nil {
			return err
		}

		return nil
	}

	return err
}

func (a *Account) FetchChannels(q *request.Query) ([]Channel, error) {
	cp := NewChannelParticipant()
	// fetch channel ids
	cids, err := cp.FetchParticipatedChannelIds(a, q)
	if err != nil {
		return nil, err
	}

	// fetch channels by their ids
	channels, err := NewChannel().FetchByIds(cids)
	if err != nil {
		return nil, err
	}

	return channels, nil
}

// TO-DO
// Control functions and remove ?
func (a *Account) Follow(targetId int64) (*ChannelParticipant, error) {
	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err == nil {
		return c.AddParticipant(targetId)
	}

	if err == bongo.RecordNotFound {
		c, err := a.CreateFollowingFeedChannel()
		if err != nil {
			return nil, err
		}
		return c.AddParticipant(targetId)
	}

	return nil, err
}

// TO-DO
// Control functions and remove ?
func (a *Account) Unfollow(targetId int64) (*Account, error) {
	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err != nil {
		return nil, err
	}

	return a, c.RemoveParticipant(targetId)
}

func (a *Account) FetchFollowerIds(q *request.Query) ([]int64, error) {
	followerIds := make([]int64, 0)
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c, err := a.FetchChannel(Channel_TYPE_FOLLOWERS)
	if err != nil {
		return followerIds, err
	}

	participants, err := c.FetchParticipantIds(q)
	if err != nil {
		return followerIds, err
	}

	return participants, nil
}

// FetchChannel fetchs the channel of the account
//
// Channel_TYPE_GROUP as parameter returns error , in the tests!!!!
// TO-DO, other types dont return error
//
// Tests are done
func (a *Account) FetchChannel(channelType string) (*Channel, error) {
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c := NewChannel()
	selector := map[string]interface{}{
		"creator_id":    a.Id,
		"type_constant": channelType,
	}

	if err := c.One(bongo.NewQS(selector)); err != nil {
		return nil, err
	}

	return c, nil
}

// Tests are done.
func (a *Account) ByNick(nick string) error {
	if nick == "" {
		return ErrNickIsNotSet
	}

	selector := map[string]interface{}{
		"nick": nick,
	}

	return a.One(bongo.NewQS(selector))
}

// Tests are done.
func (a *Account) MarkAsTroll() error {
	if a.Id == 0 {
		return ErrAccountIdIsNotSet
	}

	if err := a.ById(a.Id); err != nil {
		return err
	}

	// once, mongo sync problem happened and we couldnt mark the user as troll
	// in social api, in order to prevent it from happening again, i am removing
	// this check ~ CS

	// // do not try to mark twice
	// if a.IsTroll {
	// 	return fmt.Errorf("account is already a troll %d", a.Id)
	// }

	a.IsTroll = true
	if err := a.Update(); err != nil {
		return err
	}

	if err := bongo.B.PublishEvent("marked_as_troll", a); err != nil {
		return err
	}

	return nil
}

// Tests are done
func (a *Account) UnMarkAsTroll() error {
	if a.Id == 0 {
		return ErrAccountIdIsNotSet
	}

	if err := a.ById(a.Id); err != nil {
		return err
	}

	// once, mongo sync problem happened and we couldnt mark the user as troll
	// in social api, in order to prevent it from happening again, i am removing
	// this check ~ CS

	// // do not try to un-mark twice
	// if !a.IsTroll {
	// 	return fmt.Errorf("account is not a troll %d", a.Id)
	// }

	a.IsTroll = false
	if err := a.Update(); err != nil {
		return err
	}

	if err := bongo.B.PublishEvent("unmarked_as_troll", a); err != nil {
		return err
	}

	return nil
}

// Tests are done.
func (a *Account) CreateFollowingFeedChannel() (*Channel, error) {
	if a.Id == 0 {
		return nil, ErrAccountIdIsNotSet
	}

	c := NewChannel()
	c.CreatorId = a.Id
	c.Name = fmt.Sprintf("%d-FollowingFeedChannel", a.Id)
	c.GroupName = Channel_KODING_NAME
	c.Purpose = "Following Feed for Me"
	c.TypeConstant = Channel_TYPE_FOLLOWERS
	if err := c.Create(); err != nil {
		return nil, err
	}

	return c, nil
}

func (a *Account) FetchFollowerChannelIds(q *request.Query) ([]int64, error) {

	followerIds, err := a.FetchFollowerIds(q)
	if err != nil {
		return nil, err
	}

	cp := NewChannelParticipant()
	var channelIds []int64
	res := bongo.B.DB.
		Table(cp.BongoName()).
		Where(
		"creator_id IN (?) and type_constant = ?",
		followerIds,
		Channel_TYPE_FOLLOWINGFEED,
	).Find(&channelIds)

	if err := bongo.CheckErr(res); err != nil {
		return nil, err
	}

	return channelIds, nil
}

// FetchAccountById gives all information about account by id of account
//
// Tests are done.
func FetchAccountById(accountId int64) (*Account, error) {
	a := NewAccount()
	if err := a.ById(accountId); err != nil {
		return nil, err
	}

	return a, nil
}

// FetchOldIdsByAccountIds takes slice as parameter
//
// Tests are done
func FetchOldIdsByAccountIds(accountIds []int64) ([]string, error) {
	oldIds := make([]string, 0)

	if len(accountIds) == 0 {
		return oldIds, nil
	}

	var accounts []Account
	account := Account{}

	err := bongo.B.FetchByIds(account, &accounts, accountIds)
	if err != nil {
		return oldIds, nil
	}

	for _, account := range accounts {
		// The append built-in function appends elements to the end of a slice
		oldIds = append(oldIds, account.OldId)
	}

	return oldIds, nil
}

func FetchAccountsByNicks(nicks []string) ([]Account, error) {
	var accounts []Account

	if len(nicks) == 0 {
		return accounts, nil
	}

	a := NewAccount()
	res := bongo.B.DB.
		Table(a.BongoName()).
		Where("nick in (?)", nicks).Find(&accounts)

	if err := bongo.CheckErr(res); err != nil {
		return nil, err
	}

	return accounts, nil
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Channel struct {
	// unique identifier of the channel
	Id int64 `json:"id,string"`

	// Name of the channel
	Name string `json:"name"                         sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Creator of the channel
	CreatorId int64 `json:"creatorId,string"         sql:"NOT NULL"`

	// Name of the group which channel is belong to
	GroupName string `json:"groupName"               sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Purpose of the channel
	Purpose string `json:"purpose"`

	// Secret key of the channel for event propagation purposes
	// we can put this key into another table?
	SecretKey string `json:"-"`

	// Type of the channel
	TypeConstant string `json:"typeConstant"         sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Privacy constant of the channel
	PrivacyConstant string `json:"privacyConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of the channel
	CreatedAt time.Time `json:"createdAt"            sql:"NOT NULL"`

	// Modification date of the channel
	UpdatedAt time.Time `json:"updatedAt"            sql:"NOT NULL"`

	// Deletion date of the channel
	DeletedAt time.Time `json:"deletedAt"`
}

// to-do check for allowed channels
const (
	// TYPES
	Channel_TYPE_GROUP           = "group"
	Channel_TYPE_TOPIC           = "topic"
	Channel_TYPE_FOLLOWINGFEED   = "followingfeed"
	Channel_TYPE_FOLLOWERS       = "followers"
	Channel_TYPE_CHAT            = "chat"
	Channel_TYPE_PINNED_ACTIVITY = "pinnedactivity"
	Channel_TYPE_PRIVATE_MESSAGE = "privatemessage"
	Channel_TYPE_DEFAULT         = "default"
	// Privacy
	Channel_PRIVACY_PUBLIC  = "public"
	Channel_PRIVACY_PRIVATE = "private"
	// Koding Group Name
	Channel_KODING_NAME = "koding"
)

func NewChannel() *Channel {
	return &Channel{
		Name:            "Channel" + RandomName(),
		CreatorId:       0,
		GroupName:       Channel_KODING_NAME,
		Purpose:         "",
		SecretKey:       "",
		TypeConstant:    Channel_TYPE_DEFAULT,
		PrivacyConstant: Channel_PRIVACY_PRIVATE,
	}
}

func NewPrivateMessageChannel(creatorId int64, groupName string) *Channel {
	c := NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.Name = RandomName()
	c.TypeConstant = Channel_TYPE_PRIVATE_MESSAGE
	c.PrivacyConstant = Channel_PRIVACY_PRIVATE
	c.Purpose = ""
	return c
}

func (c *Channel) BeforeCreate() {
	c.CreatedAt = time.Now().UTC()
	c.UpdatedAt = time.Now().UTC()
	c.DeletedAt = ZeroDate()
}

func (c *Channel) BeforeUpdate() {
	c.UpdatedAt = time.Now()
}

func (c Channel) GetId() int64 {
	return c.Id
}

func (c Channel) TableName() string {
	return "api.channel"
}

func (c *Channel) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *Channel) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c Channel) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *Channel) Update() error {
	if c.Name == "" || c.GroupName == "" {
		return fmt.Errorf("Validation failed %s - %s", c.Name, c.GroupName)
	}

	return bongo.B.Update(c)
}

func (c *Channel) Create() error {
	if c.Name == "" || c.GroupName == "" || c.TypeConstant == "" {
		return fmt.Errorf("Validation failed %s - %s -%s", c.Name, c.GroupName, c.TypeConstant)
	}

	// golang returns -1 if item not in the string
	if strings.Index(c.Name, " ") > -1 {
		return fmt.Errorf("Channel name %q has empty space in it", c.Name)
	}

	if c.TypeConstant == Channel_TYPE_GROUP ||
		c.TypeConstant == Channel_TYPE_FOLLOWERS /* we can add more types here */ {

		var selector map[string]interface{}
		switch c.TypeConstant {
		case Channel_TYPE_GROUP:
			selector = map[string]interface{}{
				"group_name":    c.GroupName,
				"type_constant": c.TypeConstant,
			}
		case Channel_TYPE_FOLLOWERS:
			selector = map[string]interface{}{
				"creator_id":    c.CreatorId,
				"type_constant": c.TypeConstant,
			}
		}

		// if err is nil
		// it means we already have that channel
		err := c.One(bongo.NewQS(selector))
		if err == nil {
			return nil
			// return fmt.Errorf("%s typed channel is already created before for %s group", c.TypeConstant, c.GroupName)
		}

		if err != gorm.RecordNotFound {
			return err
		}

	}

	return bongo.B.Create(c)
}

func (c *Channel) Delete() error {
	return bongo.B.Delete(c)
}

func (c *Channel) ById(id int64) error {
	return bongo.B.ById(c, id)
}

func (c *Channel) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *Channel) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *Channel) FetchByIds(ids []int64) ([]Channel, error) {
	var channels []Channel

	if len(ids) == 0 {
		return channels, nil
	}

	if err := bongo.B.FetchByIds(c, &channels, ids); err != nil {
		return nil, err
	}
	return channels, nil
}

func (c *Channel) AddParticipant(participantId int64) (*ChannelParticipant, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	if err != nil && err != gorm.RecordNotFound {
		return nil, err
	}

	// if we have this record in DB
	if cp.Id != 0 {
		// if status is not active
		if cp.StatusConstant == ChannelParticipant_STATUS_ACTIVE {
			return nil, errors.New(fmt.Sprintf("Account %d is already a participant of channel %d", cp.AccountId, cp.ChannelId))
		}
		cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE
		if err := cp.Update(); err != nil {
			return nil, err
		}
		return cp, nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE

	if err := cp.Create(); err != nil {
		return nil, err
	}

	return cp, nil
}

func (c *Channel) RemoveParticipant(participantId int64) error {
	if c.Id == 0 {
		return errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	// if user is not in this channel, do nothing
	if err == gorm.RecordNotFound {
		return nil
	}

	if err != nil {
		return err
	}

	if cp.StatusConstant == ChannelParticipant_STATUS_LEFT {
		return nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_LEFT
	if err := cp.Update(); err != nil {
		return err
	}

	return nil
}

func (c *Channel) FetchParticipantIds() ([]int64, error) {
	var participantIds []int64

	if c.Id == 0 {
		return participantIds, errors.New("Channel Id is not set")
	}

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.Id,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
		Pluck: "account_id",
	}

	cp := NewChannelParticipant()
	err := cp.Some(&participantIds, query)
	if err != nil {
		return nil, err
	}

	return participantIds, nil
}

func (c *Channel) AddMessage(messageId int64) (*ChannelMessageList, error) {
	cml, err := c.FetchMessageList(messageId)
	if err == nil {
		return nil, errors.New("Message is already in the channel")
	}

	// silence record not found err
	if err != gorm.RecordNotFound {
		return nil, err
	}

	cml.ChannelId = c.Id
	cml.MessageId = messageId

	if err := cml.Create(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) RemoveMessage(messageId int64) (*ChannelMessageList, error) {
	cml, err := c.FetchMessageList(messageId)
	if err != nil {
		return nil, err
	}

	if err := cml.Delete(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) FetchMessageList(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}

	return cml, cml.One(bongo.NewQS(selector))
}

func (c *Channel) FetchChannelIdByNameAndGroupName(name, groupName string) (int64, error) {
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"name":       name,
			"group_name": groupName,
		},
		Pagination: *bongo.NewPagination(1, 0),
		Pluck:      "id",
	}
	var ids []int64
	if err := c.Some(&ids, query); err != nil {
		return 0, err
	}

	if ids == nil {
		return 0, gorm.RecordNotFound
	}

	if len(ids) == 0 {
		return 0, gorm.RecordNotFound
	}

	return ids[0], nil
}

func (c *Channel) Search(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := bongo.B.DB.Table(c.TableName()).Limit(q.Limit)

	query = query.Where("type_constant = ?", q.Type)
	query = query.Where("privacy_constant = ?", Channel_PRIVACY_PUBLIC)
	query = query.Where("group_name = ?", q.GroupName)
	query = query.Where("name like ?", q.Name+"%")

	if err := bongo.CheckErr(
		query.Find(&channels),
	); err != nil {
		return nil, err
	}

	if channels == nil {
		return make([]Channel, 0), nil
	}

	return channels, nil
}

func (c *Channel) ByName(q *Query) (Channel, error) {
	fmt.Println("-------- FIX THIS PART ------")
	fmt.Println("TODO - check permissions here")
	fmt.Println("-------- FIX THIS PART ------")
	var channel Channel

	if q.GroupName == "" {
		return channel, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	query := bongo.B.DB.Table(c.TableName()).Limit(q.Limit)

	query = query.Where("type_constant = ?", q.Type)
	query = query.Where("group_name = ?", q.GroupName)
	query = query.Where("name = ?", q.Name)

	return channel, query.Find(&channel).Error
}

func (c *Channel) List(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"group_name": q.GroupName,
		},
		Pagination: *bongo.NewPagination(q.Limit, q.Skip),
	}

	if q.Type != "" {
		query.Selector["type_constant"] = q.Type
	}

	err := c.Some(&channels, query)
	if err != nil {
		return nil, err
	}

	if channels == nil {
		return make([]Channel, 0), nil
	}

	return channels, nil
}

func (c *Channel) FetchLastMessage() (*ChannelMessage, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": c.Id,
		},
		Sort: map[string]string{
			"added_at": "DESC",
		},
		Pagination: *bongo.NewPagination(1, 0),
		Pluck:      "message_id",
	}

	var messageIds []int64
	err := cml.Some(&messageIds, query)
	if err != nil {
		return nil, err
	}

	if messageIds == nil || len(messageIds) == 0 {
		return nil, nil
	}

	cm := NewChannelMessage()
	if err := cm.ById(messageIds[0]); err != nil {
		return nil, err
	}

	return cm, nil
}

func (c *Channel) FetchPinnedActivityChannel(accountId int64, groupName string) error {
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"creator_id":    accountId,
			"group_name":    groupName,
			"type_constant": Channel_TYPE_PINNED_ACTIVITY,
		},
	}

	return c.One(query)
}
<commit_msg>social: FetchOldIdsByAccountIds won't return recordnotfound error<commit_after>package models

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Channel struct {
	// unique identifier of the channel
	Id int64 `json:"id,string"`

	// Name of the channel
	Name string `json:"name"                         sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Creator of the channel
	CreatorId int64 `json:"creatorId,string"         sql:"NOT NULL"`

	// Name of the group which channel is belong to
	GroupName string `json:"groupName"               sql:"NOT NULL;TYPE:VARCHAR(200);"`

	// Purpose of the channel
	Purpose string `json:"purpose"`

	// Secret key of the channel for event propagation purposes
	// we can put this key into another table?
	SecretKey string `json:"-"`

	// Type of the channel
	TypeConstant string `json:"typeConstant"         sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Privacy constant of the channel
	PrivacyConstant string `json:"privacyConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of the channel
	CreatedAt time.Time `json:"createdAt"            sql:"NOT NULL"`

	// Modification date of the channel
	UpdatedAt time.Time `json:"updatedAt"            sql:"NOT NULL"`

	// Deletion date of the channel
	DeletedAt time.Time `json:"deletedAt"`
}

// to-do check for allowed channels
const (
	// TYPES
	Channel_TYPE_GROUP           = "group"
	Channel_TYPE_TOPIC           = "topic"
	Channel_TYPE_FOLLOWINGFEED   = "followingfeed"
	Channel_TYPE_FOLLOWERS       = "followers"
	Channel_TYPE_CHAT            = "chat"
	Channel_TYPE_PINNED_ACTIVITY = "pinnedactivity"
	Channel_TYPE_PRIVATE_MESSAGE = "privatemessage"
	Channel_TYPE_DEFAULT         = "default"
	// Privacy
	Channel_PRIVACY_PUBLIC  = "public"
	Channel_PRIVACY_PRIVATE = "private"
	// Koding Group Name
	Channel_KODING_NAME = "koding"
)

func NewChannel() *Channel {
	return &Channel{
		Name:            "Channel" + RandomName(),
		CreatorId:       0,
		GroupName:       Channel_KODING_NAME,
		Purpose:         "",
		SecretKey:       "",
		TypeConstant:    Channel_TYPE_DEFAULT,
		PrivacyConstant: Channel_PRIVACY_PRIVATE,
	}
}

func NewPrivateMessageChannel(creatorId int64, groupName string) *Channel {
	c := NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.Name = RandomName()
	c.TypeConstant = Channel_TYPE_PRIVATE_MESSAGE
	c.PrivacyConstant = Channel_PRIVACY_PRIVATE
	c.Purpose = ""
	return c
}

func (c *Channel) BeforeCreate() {
	c.CreatedAt = time.Now().UTC()
	c.UpdatedAt = time.Now().UTC()
	c.DeletedAt = ZeroDate()
}

func (c *Channel) BeforeUpdate() {
	c.UpdatedAt = time.Now()
}

func (c Channel) GetId() int64 {
	return c.Id
}

func (c Channel) TableName() string {
	return "api.channel"
}

func (c *Channel) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *Channel) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c Channel) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *Channel) Update() error {
	if c.Name == "" || c.GroupName == "" {
		return fmt.Errorf("Validation failed %s - %s", c.Name, c.GroupName)
	}

	return bongo.B.Update(c)
}

func (c *Channel) Create() error {
	if c.Name == "" || c.GroupName == "" || c.TypeConstant == "" {
		return fmt.Errorf("Validation failed %s - %s -%s", c.Name, c.GroupName, c.TypeConstant)
	}

	// golang returns -1 if item not in the string
	if strings.Index(c.Name, " ") > -1 {
		return fmt.Errorf("Channel name %q has empty space in it", c.Name)
	}

	if c.TypeConstant == Channel_TYPE_GROUP ||
		c.TypeConstant == Channel_TYPE_FOLLOWERS /* we can add more types here */ {

		var selector map[string]interface{}
		switch c.TypeConstant {
		case Channel_TYPE_GROUP:
			selector = map[string]interface{}{
				"group_name":    c.GroupName,
				"type_constant": c.TypeConstant,
			}
		case Channel_TYPE_FOLLOWERS:
			selector = map[string]interface{}{
				"creator_id":    c.CreatorId,
				"type_constant": c.TypeConstant,
			}
		}

		// if err is nil
		// it means we already have that channel
		err := c.One(bongo.NewQS(selector))
		if err == nil {
			return nil
			// return fmt.Errorf("%s typed channel is already created before for %s group", c.TypeConstant, c.GroupName)
		}

		if err != gorm.RecordNotFound {
			return err
		}

	}

	return bongo.B.Create(c)
}

func (c *Channel) Delete() error {
	return bongo.B.Delete(c)
}

func (c *Channel) ById(id int64) error {
	return bongo.B.ById(c, id)
}

func (c *Channel) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *Channel) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func (c *Channel) FetchByIds(ids []int64) ([]Channel, error) {
	var channels []Channel

	if len(ids) == 0 {
		return channels, nil
	}

	if err := bongo.B.FetchByIds(c, &channels, ids); err != nil {
		return nil, err
	}
	return channels, nil
}

func (c *Channel) AddParticipant(participantId int64) (*ChannelParticipant, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	if err != nil && err != gorm.RecordNotFound {
		return nil, err
	}

	// if we have this record in DB
	if cp.Id != 0 {
		// if status is not active
		if cp.StatusConstant == ChannelParticipant_STATUS_ACTIVE {
			return nil, errors.New(fmt.Sprintf("Account %d is already a participant of channel %d", cp.AccountId, cp.ChannelId))
		}
		cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE
		if err := cp.Update(); err != nil {
			return nil, err
		}
		return cp, nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_ACTIVE

	if err := cp.Create(); err != nil {
		return nil, err
	}

	return cp, nil
}

func (c *Channel) RemoveParticipant(participantId int64) error {
	if c.Id == 0 {
		return errors.New("Channel Id is not set")
	}

	cp := NewChannelParticipant()
	cp.ChannelId = c.Id
	cp.AccountId = participantId

	err := cp.FetchParticipant()
	// if user is not in this channel, do nothing
	if err == gorm.RecordNotFound {
		return nil
	}

	if err != nil {
		return err
	}

	if cp.StatusConstant == ChannelParticipant_STATUS_LEFT {
		return nil
	}

	cp.StatusConstant = ChannelParticipant_STATUS_LEFT
	if err := cp.Update(); err != nil {
		return err
	}

	return nil
}

func (c *Channel) FetchParticipantIds() ([]int64, error) {
	var participantIds []int64

	if c.Id == 0 {
		return participantIds, errors.New("Channel Id is not set")
	}

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id":      c.Id,
			"status_constant": ChannelParticipant_STATUS_ACTIVE,
		},
		Pluck: "account_id",
	}

	cp := NewChannelParticipant()
	err := cp.Some(&participantIds, query)
	if err != nil {
		return nil, err
	}

	return participantIds, nil
}

func (c *Channel) AddMessage(messageId int64) (*ChannelMessageList, error) {
	cml, err := c.FetchMessageList(messageId)
	if err == nil {
		return nil, errors.New("Message is already in the channel")
	}

	// silence record not found err
	if err != gorm.RecordNotFound {
		return nil, err
	}

	cml.ChannelId = c.Id
	cml.MessageId = messageId

	if err := cml.Create(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) RemoveMessage(messageId int64) (*ChannelMessageList, error) {
	cml, err := c.FetchMessageList(messageId)
	if err != nil {
		return nil, err
	}

	if err := cml.Delete(); err != nil {
		return nil, err
	}

	return cml, nil
}

func (c *Channel) FetchMessageList(messageId int64) (*ChannelMessageList, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	selector := map[string]interface{}{
		"channel_id": c.Id,
		"message_id": messageId,
	}

	return cml, cml.One(bongo.NewQS(selector))
}

func (c *Channel) FetchChannelIdByNameAndGroupName(name, groupName string) (int64, error) {
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"name":       name,
			"group_name": groupName,
		},
		Pagination: *bongo.NewPagination(1, 0),
		Pluck:      "id",
	}
	var ids []int64
	if err := c.Some(&ids, query); err != nil {
		return 0, err
	}

	if ids == nil {
		return 0, gorm.RecordNotFound
	}

	if len(ids) == 0 {
		return 0, gorm.RecordNotFound
	}

	return ids[0], nil
}

func (c *Channel) Search(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := bongo.B.DB.Table(c.TableName()).Limit(q.Limit)

	query = query.Where("type_constant = ?", q.Type)
	query = query.Where("privacy_constant = ?", Channel_PRIVACY_PUBLIC)
	query = query.Where("group_name = ?", q.GroupName)
	query = query.Where("name like ?", q.Name+"%")

	if err := bongo.CheckErr(
		query.Find(&channels),
	); err != nil {
		return nil, err
	}

	if channels == nil {
		return make([]Channel, 0), nil
	}

	return channels, nil
}

func (c *Channel) ByName(q *Query) (Channel, error) {
	fmt.Println("-------- FIX THIS PART ------")
	fmt.Println("TODO - check permissions here")
	fmt.Println("-------- FIX THIS PART ------")
	var channel Channel

	if q.GroupName == "" {
		return channel, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	query := bongo.B.DB.Table(c.TableName()).Limit(q.Limit)

	query = query.Where("type_constant = ?", q.Type)
	query = query.Where("group_name = ?", q.GroupName)
	query = query.Where("name = ?", q.Name)

	return channel, bongo.CheckErr(query.Find(&channel))
}

func (c *Channel) List(q *Query) ([]Channel, error) {

	if q.GroupName == "" {
		return nil, fmt.Errorf("Query doesnt have any Group info %+v", q)
	}

	var channels []Channel

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"group_name": q.GroupName,
		},
		Pagination: *bongo.NewPagination(q.Limit, q.Skip),
	}

	if q.Type != "" {
		query.Selector["type_constant"] = q.Type
	}

	err := c.Some(&channels, query)
	if err != nil {
		return nil, err
	}

	if channels == nil {
		return make([]Channel, 0), nil
	}

	return channels, nil
}

func (c *Channel) FetchLastMessage() (*ChannelMessage, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel Id is not set")
	}

	cml := NewChannelMessageList()
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": c.Id,
		},
		Sort: map[string]string{
			"added_at": "DESC",
		},
		Pagination: *bongo.NewPagination(1, 0),
		Pluck:      "message_id",
	}

	var messageIds []int64
	err := cml.Some(&messageIds, query)
	if err != nil {
		return nil, err
	}

	if messageIds == nil || len(messageIds) == 0 {
		return nil, nil
	}

	cm := NewChannelMessage()
	if err := cm.ById(messageIds[0]); err != nil {
		return nil, err
	}

	return cm, nil
}

func (c *Channel) FetchPinnedActivityChannel(accountId int64, groupName string) error {
	query := &bongo.Query{
		Selector: map[string]interface{}{
			"creator_id":    accountId,
			"group_name":    groupName,
			"type_constant": Channel_TYPE_PINNED_ACTIVITY,
		},
	}

	return c.One(query)
}
<|endoftext|>


<commit_before>package gocd

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

// Equal is true if the two materials are logically equivalent. Not neccesarily literally equal.
func (m Material) Equal(a *Material) (isEqual bool, err error) {
	if m.Type != a.Type {
		return false, nil
	}
	switch m.Type {
	case "git":
		if isEqual, err = m.Attributes.equal(a.Attributes); err != nil {
			return false, err
		}
	default:
		panic(fmt.Errorf("Material comparison not implemented for '%s'", m.Type))
	}
	return isEqual, nil
}

func (m *Material) UnmarshalJSON(b []byte) error {
	temp := map[string]interface{}{}
	json.Unmarshal(b, &temp)

	switch m.Type = temp["type"].(string); strings.ToLower(m.Type) {
	case "git":
		m.Attributes = &MaterialAttributesGit{}
	default:
		return fmt.Errorf("Unexpected Material type: '%s'", m.Type)
	}

	for key, value := range temp {
		if value == nil {
			continue
		}
		switch key {
		case "attributes":
			m.Attributes.UnmarshallInterface(temp["attributes"].(map[string]interface{}))
		case "fingerprint":
			m.Fingerprint = value.(string)
		case "description":
			m.Description = value.(string)
		case "type":
			continue
		default:
			return fmt.Errorf("Unexpected key: '%s'", key)
		}
	}

	return nil
}

func (mag *MaterialAttributesGit) equal(a2i interface{}) (bool, error) {
	//var a2 MaterialAttributesGit
	var ok bool
	a2, ok := a2i.(*MaterialAttributesGit)
	if !ok {
		return false, errors.New("Can only compare with same material type.")
	}
	urlsEqual := mag.URL == a2.URL
	branchesEqual := mag.Branch == a2.Branch ||
		mag.Branch == "" && a2.Branch == "master" ||
		mag.Branch == "master" && a2.Branch == ""

	if !urlsEqual {
		return false, nil
	}
	return branchesEqual, nil
}

func (mag *MaterialAttributesGit) UnmarshallInterface(i map[string]interface{}) {
	for key, value := range i {
		if value == nil {
			continue
		}
		switch key {
		case "name":
			mag.Name = value.(string)
		case "url":
			mag.URL = value.(string)
		case "auto_update":
			mag.AutoUpdate = value.(bool)
		case "branch":
			mag.Branch = value.(string)
		case "submodule_folder":
			mag.SubmoduleFolder = value.(string)
		case "destination":
			mag.Destination = value.(string)
		case "shallow_clone":
			mag.ShallowClone = value.(bool)
		case "invert_filter":
			mag.InvertFilter = value.(bool)
			//case "filter":
			//	mag.Filter = value.(string)
		default:
			fmt.Println(value)
			fmt.Println(key)
		}
	}
}
<commit_msg>Added svn material type<commit_after>package gocd

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

// Equal is true if the two materials are logically equivalent. Not neccesarily literally equal.
func (m Material) Equal(a *Material) (isEqual bool, err error) {
	if m.Type != a.Type {
		return false, nil
	}
	switch m.Type {
	case "git":
		if isEqual, err = m.Attributes.equal(a.Attributes); err != nil {
			return false, err
		}
	default:
		panic(fmt.Errorf("Material comparison not implemented for '%s'", m.Type))
	}
	return isEqual, nil
}

func (m *Material) UnmarshalJSON(b []byte) error {
	temp := map[string]interface{}{}
	json.Unmarshal(b, &temp)

	switch m.Type = temp["type"].(string); strings.ToLower(m.Type) {
	case "git":
		m.Attributes = &MaterialAttributesGit{}
	case "svn":
		m.Attributes = &MaterialAttributesSvn{}
	default:
		return fmt.Errorf("Unexpected Material type: '%s'", m.Type)
	}

	for key, value := range temp {
		if value == nil {
			continue
		}
		switch key {
		case "attributes":
			m.Attributes.UnmarshallInterface(temp["attributes"].(map[string]interface{}))
		case "fingerprint":
			m.Fingerprint = value.(string)
		case "description":
			m.Description = value.(string)
		case "type":
			continue
		default:
			return fmt.Errorf("Unexpected key: '%s'", key)
		}
	}

	return nil
}

func (mag *MaterialAttributesGit) equal(a2i interface{}) (bool, error) {
	//var a2 MaterialAttributesGit
	var ok bool
	a2, ok := a2i.(*MaterialAttributesGit)
	if !ok {
		return false, errors.New("Can only compare with same material type.")
	}
	urlsEqual := mag.URL == a2.URL
	branchesEqual := mag.Branch == a2.Branch ||
		mag.Branch == "" && a2.Branch == "master" ||
		mag.Branch == "master" && a2.Branch == ""

	if !urlsEqual {
		return false, nil
	}
	return branchesEqual, nil
}

func (mag *MaterialAttributesGit) UnmarshallInterface(i map[string]interface{}) {
	for key, value := range i {
		if value == nil {
			continue
		}
		switch key {
		case "name":
			mag.Name = value.(string)
		case "url":
			mag.URL = value.(string)
		case "auto_update":
			mag.AutoUpdate = value.(bool)
		case "branch":
			mag.Branch = value.(string)
		case "submodule_folder":
			mag.SubmoduleFolder = value.(string)
		case "destination":
			mag.Destination = value.(string)
		case "shallow_clone":
			mag.ShallowClone = value.(bool)
		case "invert_filter":
			mag.InvertFilter = value.(bool)
			//case "filter":
			//	mag.Filter = value.(string)
		default:
			fmt.Println(value)
			fmt.Println(key)
		}
	}
}
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"reflect"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func GetDataCatalogTagTemplateCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//datacatalog.googleapis.com/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetDataCatalogTagTemplateApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "datacatalog.googleapis.com/TagTemplate",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/datacatalog/v1/rest",
				DiscoveryName:        "TagTemplate",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetDataCatalogTagTemplateApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	displayNameProp, err := expandDataCatalogTagTemplateDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	fieldsProp, err := expandDataCatalogTagTemplateFields(d.Get("fields"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("fields"); !isEmptyValue(reflect.ValueOf(fieldsProp)) && (ok || !reflect.DeepEqual(v, fieldsProp)) {
		obj["fields"] = fieldsProp
	}

	return obj, nil
}

func expandDataCatalogTagTemplateDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFields(v interface{}, d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	if v == nil {
		return map[string]interface{}{}, nil
	}
	m := make(map[string]interface{})
	for _, raw := range v.(*schema.Set).List() {
		original := raw.(map[string]interface{})
		transformed := make(map[string]interface{})

		transformedName, err := expandDataCatalogTagTemplateFieldsName(original["name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
			transformed["name"] = transformedName
		}

		transformedDisplayName, err := expandDataCatalogTagTemplateFieldsDisplayName(original["display_name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !isEmptyValue(val) {
			transformed["displayName"] = transformedDisplayName
		}

		transformedType, err := expandDataCatalogTagTemplateFieldsType(original["type"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedType); val.IsValid() && !isEmptyValue(val) {
			transformed["type"] = transformedType
		}

		transformedIsRequired, err := expandDataCatalogTagTemplateFieldsIsRequired(original["is_required"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedIsRequired); val.IsValid() && !isEmptyValue(val) {
			transformed["isRequired"] = transformedIsRequired
		}

		transformedOrder, err := expandDataCatalogTagTemplateFieldsOrder(original["order"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedOrder); val.IsValid() && !isEmptyValue(val) {
			transformed["order"] = transformedOrder
		}

		transformedFieldId, err := expandString(original["field_id"], d, config)
		if err != nil {
			return nil, err
		}
		m[transformedFieldId] = transformed
	}
	return m, nil
}

func expandDataCatalogTagTemplateFieldsName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedPrimitiveType, err := expandDataCatalogTagTemplateFieldsTypePrimitiveType(original["primitive_type"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedPrimitiveType); val.IsValid() && !isEmptyValue(val) {
		transformed["primitiveType"] = transformedPrimitiveType
	}

	transformedEnumType, err := expandDataCatalogTagTemplateFieldsTypeEnumType(original["enum_type"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedEnumType); val.IsValid() && !isEmptyValue(val) {
		transformed["enumType"] = transformedEnumType
	}

	return transformed, nil
}

func expandDataCatalogTagTemplateFieldsTypePrimitiveType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedAllowedValues, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(original["allowed_values"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAllowedValues); val.IsValid() && !isEmptyValue(val) {
		transformed["allowedValues"] = transformedAllowedValues
	}

	return transformed, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	l := v.([]interface{})
	req := make([]interface{}, 0, len(l))
	for _, raw := range l {
		if raw == nil {
			continue
		}
		original := raw.(map[string]interface{})
		transformed := make(map[string]interface{})

		transformedDisplayName, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(original["display_name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !isEmptyValue(val) {
			transformed["displayName"] = transformedDisplayName
		}

		req = append(req, transformed)
	}
	return req, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsIsRequired(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsOrder(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<commit_msg>Add support for description to tag template fields (#8810) (#4650) (#674)<commit_after>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"reflect"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func GetDataCatalogTagTemplateCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//datacatalog.googleapis.com/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetDataCatalogTagTemplateApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "datacatalog.googleapis.com/TagTemplate",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/datacatalog/v1/rest",
				DiscoveryName:        "TagTemplate",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetDataCatalogTagTemplateApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	displayNameProp, err := expandDataCatalogTagTemplateDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	fieldsProp, err := expandDataCatalogTagTemplateFields(d.Get("fields"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("fields"); !isEmptyValue(reflect.ValueOf(fieldsProp)) && (ok || !reflect.DeepEqual(v, fieldsProp)) {
		obj["fields"] = fieldsProp
	}

	return obj, nil
}

func expandDataCatalogTagTemplateDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFields(v interface{}, d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	if v == nil {
		return map[string]interface{}{}, nil
	}
	m := make(map[string]interface{})
	for _, raw := range v.(*schema.Set).List() {
		original := raw.(map[string]interface{})
		transformed := make(map[string]interface{})

		transformedName, err := expandDataCatalogTagTemplateFieldsName(original["name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) {
			transformed["name"] = transformedName
		}

		transformedDisplayName, err := expandDataCatalogTagTemplateFieldsDisplayName(original["display_name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !isEmptyValue(val) {
			transformed["displayName"] = transformedDisplayName
		}

		transformedDescription, err := expandDataCatalogTagTemplateFieldsDescription(original["description"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
			transformed["description"] = transformedDescription
		}

		transformedType, err := expandDataCatalogTagTemplateFieldsType(original["type"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedType); val.IsValid() && !isEmptyValue(val) {
			transformed["type"] = transformedType
		}

		transformedIsRequired, err := expandDataCatalogTagTemplateFieldsIsRequired(original["is_required"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedIsRequired); val.IsValid() && !isEmptyValue(val) {
			transformed["isRequired"] = transformedIsRequired
		}

		transformedOrder, err := expandDataCatalogTagTemplateFieldsOrder(original["order"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedOrder); val.IsValid() && !isEmptyValue(val) {
			transformed["order"] = transformedOrder
		}

		transformedFieldId, err := expandString(original["field_id"], d, config)
		if err != nil {
			return nil, err
		}
		m[transformedFieldId] = transformed
	}
	return m, nil
}

func expandDataCatalogTagTemplateFieldsName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedPrimitiveType, err := expandDataCatalogTagTemplateFieldsTypePrimitiveType(original["primitive_type"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedPrimitiveType); val.IsValid() && !isEmptyValue(val) {
		transformed["primitiveType"] = transformedPrimitiveType
	}

	transformedEnumType, err := expandDataCatalogTagTemplateFieldsTypeEnumType(original["enum_type"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedEnumType); val.IsValid() && !isEmptyValue(val) {
		transformed["enumType"] = transformedEnumType
	}

	return transformed, nil
}

func expandDataCatalogTagTemplateFieldsTypePrimitiveType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	l := v.([]interface{})
	if len(l) == 0 || l[0] == nil {
		return nil, nil
	}
	raw := l[0]
	original := raw.(map[string]interface{})
	transformed := make(map[string]interface{})

	transformedAllowedValues, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(original["allowed_values"], d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedAllowedValues); val.IsValid() && !isEmptyValue(val) {
		transformed["allowedValues"] = transformedAllowedValues
	}

	return transformed, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValues(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	v = v.(*schema.Set).List()
	l := v.([]interface{})
	req := make([]interface{}, 0, len(l))
	for _, raw := range l {
		if raw == nil {
			continue
		}
		original := raw.(map[string]interface{})
		transformed := make(map[string]interface{})

		transformedDisplayName, err := expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(original["display_name"], d, config)
		if err != nil {
			return nil, err
		} else if val := reflect.ValueOf(transformedDisplayName); val.IsValid() && !isEmptyValue(val) {
			transformed["displayName"] = transformedDisplayName
		}

		req = append(req, transformed)
	}
	return req, nil
}

func expandDataCatalogTagTemplateFieldsTypeEnumTypeAllowedValuesDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsIsRequired(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandDataCatalogTagTemplateFieldsOrder(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<|endoftext|>


<commit_before>package errors

import "sync"

// ErrorList is used to chain a list of potential errors
type ErrorList struct {
	mux  sync.RWMutex
	errs []error
}

// Error will return the string-form of the errors
func (e *ErrorList) Error() string {
	if e == nil {
		return ""
	}

	e.mux.RLock()
	defer e.mux.RUnlock()

	if len(e.errs) == 0 {
		return ""
	}

	if len(e.errs) == 1 {
		return e.errs[0].Error()
	}

	b := []byte("the following errors occured:\n")
	for _, err := range e.errs {
		b = append(b, err.Error()...)
		b = append(b, '\n')
	}

	return string(b)
}

// Err will return an error if the errorlist is not empty
// If the errorlist is empty - nil is returned
func (e *ErrorList) Err() (err error) {
	if e == nil {
		return
	}
	e.mux.RLock()
	switch len(e.errs) {
	case 0: // do nothing
	case 1:
		err = e.errs[0]
	default:
		err = e
	}
	e.mux.RLock()
	return
}

// Push will push an error to the errorlist
// If the errorlist is nil, it will be created
func (e *ErrorList) Push(err error) {
	if err == nil {
		return
	}
	if e == nil {
		*e = ErrorList{}
	}

	e.mux.Lock()
	e.errs = append(e.errs, err)
	e.mux.Unlock()
}

// ForEach will iterate through all of the errors within the error list
func (e *ErrorList) ForEach(fn func(error)) {
	if e == nil {
		return
	}
	e.mux.RLock()
	for _, err := range e.errs {
		fn(err)
	}
	e.mux.RUnlock()
}

// Len will return the length of the inner errors list
func (e *ErrorList) Len() (n int) {
	if e == nil {
		return
	}
	e.mux.RLock()
	n = len(e.errs)
	e.mux.RUnlock()
	return
}
<commit_msg>few fixes<commit_after>package errors

import "sync"

// ErrorList is used to chain a list of potential errors and is thread-safe.
type ErrorList struct {
	mux  sync.RWMutex
	errs []error
}

// Error will return the string-form of the errors.
// Implements the error interface.
func (e *ErrorList) Error() string {
	if e == nil {
		return ""
	}

	e.mux.RLock()
	defer e.mux.RUnlock()

	if len(e.errs) == 0 {
		return ""
	}

	if len(e.errs) == 1 {
		return e.errs[0].Error()
	}

	b := []byte("the following errors occured:\n")
	for _, err := range e.errs {
		b = append(b, err.Error()...)
		b = append(b, '\n')
	}

	return string(b)
}

// Err will return an error if the errorlist is not empty.
// If there's only 1 error, it will be directly returned.
// If the errorlist is empty - nil is returned.
func (e *ErrorList) Err() (err error) {
	if e == nil {
		return
	}
	e.mux.RLock()
	switch len(e.errs) {
	case 0: // do nothing
	case 1:
		err = e.errs[0]
	default:
		err = e
	}
	e.mux.RLock()
	return
}

// Push will push an error to the errorlist
// If err is a errorlist, it will be merged.
// If the errorlist is nil, it will be created.
func (e *ErrorList) Push(err error) {
	if err == nil {
		return
	}

	if e == nil {
		*e = ErrorList{}
	}

	e.mux.Lock()
	switch v := err.(type) {
	case *ErrorList:
		v.ForEach(func(err error) {
			e.errs = append(e.errs, err)
		})
	default:
		e.errs = append(e.errs, err)
	}
	e.mux.Unlock()
}

// ForEach will iterate through all of the errors within the error list.
func (e *ErrorList) ForEach(fn func(error)) {
	if e == nil {
		return
	}

	e.mux.RLock()
	for _, err := range e.errs {
		fn(err)
	}
	e.mux.RUnlock()
}

// Len will return the length of the inner errors list.
func (e *ErrorList) Len() (n int) {
	if e == nil {
		return
	}

	e.mux.RLock()
	n = len(e.errs)
	e.mux.RUnlock()
	return
}
<|endoftext|>


<commit_before>package eslite

import (
	"fmt"
	"log"
	"strings"

	/*as doc v6 now use github master*/
	"github.com/olivere/elastic/v7"
	"golang.org/x/net/context"
)

//ElasticClientV7 object
type ElasticClientV7 struct {
	client   *elastic.Client
	bkt      *elastic.BulkService
	pipeline string
}

// open: connect with elasticsearch by user:pass@host:port
func (es *ElasticClientV7) Open(host string, port int, usrName, pass string) error {
	url := fmt.Sprintf("http://%s:%d", host, port)
	if strings.HasPrefix(host, "http://") || strings.HasPrefix(host, "https://") {
		url = host
	}
	fmt.Println(url)
	client, err := elastic.NewClient(elastic.SetURL(url),
		elastic.SetBasicAuth(usrName, pass), elastic.SetSniff(false))
	if err != nil {
		return err
	}
	info, code, err := client.Ping(url).Do(context.TODO())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)

	esversion, err := client.ElasticsearchVersion(url)
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch version %s\n", esversion)
	es.client = client

	/*
		BulkService will be reset after each Do call.
		In other words, you can reuse BulkService to send many batches.
		You do not have to create a new BulkService for each batch.
	*/
	es.bkt = es.client.Bulk()
	return nil
}

//patch write elastic document
func (es *ElasticClientV7) Write(index string, id string,
	typ string, v interface{}) error {
	es.bkt.Add(elastic.NewBulkIndexRequest().Index(
		index).Type(typ).Id(id).Doc(v))
	return nil
}

//begin patch write
func (es *ElasticClientV7) Begin() error {
	return nil
}

//commit patch write
func (es *ElasticClientV7) Commit() error {
	//	log.Println("DOBEFORE bulkRequest:NumberOfActions", es.bkt.NumberOfActions())
	es.bkt.Pipeline(es.pipeline)
	bulkResponse, err := es.bkt.Do(context.Background())
	if err != nil {
		log.Println(err)
		return err
	}
	if bulkResponse == nil {
		log.Fatal("expected bulkResponse to be != nil; got nil")
	}
	//	log.Println("DOAFTER buolkRequest:NumberOfActions", es.bkt.NumberOfActions())
	return err
}

//close elasticsearch connection
func (es *ElasticClientV7) Close() {
	// Use the IndexExists service to check if a specified index exists.
}

//write a document directly
func (es *ElasticClientV7) WriteDirect(index, id, typ string,
	v interface{}) error {
	_, err := es.client.Index().Pipeline(es.pipeline).Index(index).Type(typ).Id(id).BodyJson(v).Do(context.Background())
	return err
}

//set elasticsearch pipeline
func (es *ElasticClientV7) SetPipeline(pipeline string) error {
	es.pipeline = pipeline
	return nil
}
<commit_msg>elasticv7 ignore type feild<commit_after>package eslite

import (
	"fmt"
	"log"
	"strings"

	/*as doc v6 now use github master*/
	"github.com/olivere/elastic/v7"
	"golang.org/x/net/context"
)

//ElasticClientV7 object
type ElasticClientV7 struct {
	client   *elastic.Client
	bkt      *elastic.BulkService
	pipeline string
}

// open: connect with elasticsearch by user:pass@host:port
func (es *ElasticClientV7) Open(host string, port int, usrName, pass string) error {
	url := fmt.Sprintf("http://%s:%d", host, port)
	if strings.HasPrefix(host, "http://") || strings.HasPrefix(host, "https://") {
		url = host
	}
	fmt.Println(url)
	client, err := elastic.NewClient(elastic.SetURL(url),
		elastic.SetBasicAuth(usrName, pass), elastic.SetSniff(false))
	if err != nil {
		return err
	}
	info, code, err := client.Ping(url).Do(context.TODO())
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)

	esversion, err := client.ElasticsearchVersion(url)
	if err != nil {
		// Handle error
		panic(err)
	}
	fmt.Printf("Elasticsearch version %s\n", esversion)
	es.client = client

	/*
		BulkService will be reset after each Do call.
		In other words, you can reuse BulkService to send many batches.
		You do not have to create a new BulkService for each batch.
	*/
	es.bkt = es.client.Bulk()
	return nil
}

//patch write elastic document
func (es *ElasticClientV7) Write(index string, id string,
	typ string, v interface{}) error {
	es.bkt.Add(elastic.NewBulkIndexRequest().Index(
		index).Id(id).Doc(v))
	return nil
}

//begin patch write
func (es *ElasticClientV7) Begin() error {
	return nil
}

//commit patch write
func (es *ElasticClientV7) Commit() error {
	//	log.Println("DOBEFORE bulkRequest:NumberOfActions", es.bkt.NumberOfActions())
	es.bkt.Pipeline(es.pipeline)
	bulkResponse, err := es.bkt.Do(context.Background())
	if err != nil {
		log.Println(err)
		return err
	}
	if bulkResponse == nil {
		log.Fatal("expected bulkResponse to be != nil; got nil")
	}
	//	log.Println("DOAFTER buolkRequest:NumberOfActions", es.bkt.NumberOfActions())
	return err
}

//close elasticsearch connection
func (es *ElasticClientV7) Close() {
	// Use the IndexExists service to check if a specified index exists.
}

//write a document directly
func (es *ElasticClientV7) WriteDirect(index, id, typ string,
	v interface{}) error {
	_, err := es.client.Index().Pipeline(es.pipeline).Index(index).Id(id).BodyJson(v).Do(context.Background())
	return err
}

//set elasticsearch pipeline
func (es *ElasticClientV7) SetPipeline(pipeline string) error {
	es.pipeline = pipeline
	return nil
}
<|endoftext|>


<commit_before>package integration_test

import (
	"os"

	"github.com/cloudfoundry/cli/cf/i18n"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("locales", func() {
	var oldLocale string

	BeforeEach(func() {
		oldLocale = os.Getenv("LANG")
	})

	AfterEach(func() {
		os.Setenv("LANG", oldLocale)
	})

	It("exits 0 when help is run for each language", func() {
		for _, locale := range i18n.SUPPORTED_LOCALES {
			os.Setenv("LANG", locale)
			result := Cf("help")

			Eventually(result).Should(Exit(0))
		}
	})
})
<commit_msg>Give integration test more time to complete<commit_after>package integration_test

import (
	"os"
	"time"

	"github.com/cloudfoundry/cli/cf/i18n"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("locales", func() {
	var oldLocale string

	BeforeEach(func() {
		oldLocale = os.Getenv("LANG")
	})

	AfterEach(func() {
		os.Setenv("LANG", oldLocale)
	})

	It("exits 0 when help is run for each language", func() {
		for _, locale := range i18n.SUPPORTED_LOCALES {
			os.Setenv("LANG", locale)
			result := Cf("help")

			Eventually(result, 3*time.Second).Should(Exit(0))
		}
	})
})
<|endoftext|>


<commit_before>// This file was automatically generated by "compat-table.js"

package compat

type Engine uint8

const (
	Chrome Engine = iota
	Edge
	ES
	Firefox
	IOS
	Node
	Safari
)

func (e Engine) String() string {
	switch e {
	case Chrome:
		return "chrome"
	case Edge:
		return "edge"
	case ES:
		return "es"
	case Firefox:
		return "firefox"
	case IOS:
		return "ios"
	case Node:
		return "node"
	case Safari:
		return "safari"
	}
	return ""
}

type JSFeature uint64

const (
	ArbitraryModuleNamespaceNames JSFeature = 1 << iota
	ArraySpread
	Arrow
	AsyncAwait
	AsyncGenerator
	BigInt
	Class
	ClassField
	ClassPrivateAccessor
	ClassPrivateBrandCheck
	ClassPrivateField
	ClassPrivateMethod
	ClassPrivateStaticAccessor
	ClassPrivateStaticField
	ClassPrivateStaticMethod
	ClassStaticField
	Const
	DefaultArgument
	Destructuring
	DynamicImport
	ExponentOperator
	ExportStarAs
	ForAwait
	ForOf
	Generator
	Hashbang
	ImportAssertions
	ImportMeta
	Let
	LogicalAssignment
	NestedRestBinding
	NewTarget
	NullishCoalescing
	ObjectAccessors
	ObjectExtensions
	ObjectRestSpread
	OptionalCatchBinding
	OptionalChain
	RestArgument
	TemplateLiteral
	TopLevelAwait
	UnicodeEscapes
)

func (features JSFeature) Has(feature JSFeature) bool {
	return (features & feature) != 0
}

var jsTable = map[JSFeature]map[Engine][]int{
	ArbitraryModuleNamespaceNames: {
		Chrome: {90},
		Node:   {16},
	},
	ArraySpread: {
		Chrome:  {46},
		Edge:    {13},
		ES:      {2015},
		Firefox: {36},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	Arrow: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	AsyncAwait: {
		Chrome:  {55},
		Edge:    {15},
		ES:      {2017},
		Firefox: {52},
		IOS:     {11},
		Node:    {7, 6},
		Safari:  {11},
	},
	AsyncGenerator: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	BigInt: {
		Chrome:  {67},
		Edge:    {79},
		ES:      {2020},
		Firefox: {68},
		IOS:     {14},
		Node:    {10, 4},
		Safari:  {14},
	},
	Class: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	ClassField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {69},
		IOS:     {14},
		Node:    {12, 0},
		Safari:  {14},
	},
	ClassPrivateAccessor: {
		Chrome: {84},
		Edge:   {84},
		Node:   {14, 6},
	},
	ClassPrivateBrandCheck: {
		Chrome: {91},
	},
	ClassPrivateField: {
		Chrome: {84},
		Edge:   {84},
		Node:   {14, 6},
		Safari: {14, 1},
	},
	ClassPrivateMethod: {
		Chrome: {84},
		Edge:   {84},
		Node:   {14, 6},
	},
	ClassPrivateStaticAccessor: {
		Chrome: {84},
		Edge:   {84},
		Node:   {14, 6},
	},
	ClassPrivateStaticField: {
		Chrome: {74},
		Edge:   {79},
		Node:   {12, 0},
		Safari: {14, 1},
	},
	ClassPrivateStaticMethod: {
		Chrome: {84},
		Edge:   {84},
		Node:   {14, 6},
	},
	ClassStaticField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {75},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	Const: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	DefaultArgument: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Destructuring: {
		Chrome:  {51},
		Edge:    {18},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	DynamicImport: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2015},
		Firefox: {67},
		IOS:     {11},
		Node:    {13, 2},
		Safari:  {11, 1},
	},
	ExponentOperator: {
		Chrome:  {52},
		Edge:    {14},
		ES:      {2016},
		Firefox: {52},
		IOS:     {10, 3},
		Node:    {7},
		Safari:  {10, 1},
	},
	ExportStarAs: {
		Chrome:  {72},
		Edge:    {79},
		ES:      {2020},
		Firefox: {80},
		Node:    {12},
	},
	ForAwait: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	ForOf: {
		Chrome:  {51},
		Edge:    {15},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	Generator: {
		Chrome:  {50},
		Edge:    {13},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Hashbang: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {67},
		IOS:     {13, 4},
		Node:    {12, 0},
		Safari:  {13, 1},
	},
	ImportAssertions: {
		Chrome: {91},
	},
	ImportMeta: {
		Chrome:  {64},
		Edge:    {79},
		ES:      {2020},
		Firefox: {62},
		IOS:     {12},
		Node:    {10, 4},
		Safari:  {11, 1},
	},
	Let: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	LogicalAssignment: {
		Chrome:  {85},
		Edge:    {85},
		Firefox: {79},
		IOS:     {14},
		Node:    {15, 0},
		Safari:  {14},
	},
	NestedRestBinding: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2016},
		Firefox: {47},
		IOS:     {10, 3},
		Node:    {6},
		Safari:  {10, 1},
	},
	NewTarget: {
		Chrome:  {46},
		Edge:    {14},
		ES:      {2015},
		Firefox: {41},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	NullishCoalescing: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {72},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	ObjectAccessors: {
		Chrome:  {5},
		Edge:    {12},
		ES:      {5},
		Firefox: {2},
		IOS:     {6},
		Node:    {0, 10},
		Safari:  {3, 1},
	},
	ObjectExtensions: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {34},
		IOS:     {10},
		Node:    {4},
		Safari:  {10},
	},
	ObjectRestSpread: {
		ES:      {2018},
		Firefox: {55},
		IOS:     {11, 3},
		Safari:  {11, 1},
	},
	OptionalCatchBinding: {
		Chrome:  {66},
		Edge:    {79},
		ES:      {2019},
		Firefox: {58},
		IOS:     {11, 3},
		Node:    {10, 0},
		Safari:  {11, 1},
	},
	OptionalChain: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {74},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	RestArgument: {
		Chrome:  {47},
		Edge:    {12},
		ES:      {2015},
		Firefox: {43},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	TemplateLiteral: {
		Chrome:  {41},
		Edge:    {13},
		ES:      {2015},
		Firefox: {34},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
	TopLevelAwait: {
		Chrome: {89},
		Node:   {14, 8},
	},
	UnicodeEscapes: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {53},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
}

func isVersionLessThan(a []int, b []int) bool {
	for i := 0; i < len(a) && i < len(b); i++ {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}
	return len(a) < len(b)
}

// Return all features that are not available in at least one environment
func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) {
	for feature, engines := range jsTable {
		for engine, version := range constraints {
			if minVersion, ok := engines[engine]; !ok || isVersionLessThan(version, minVersion) {
				unsupported |= feature
			}
		}
	}
	return
}
<commit_msg>update the browser compat table<commit_after>// This file was automatically generated by "compat-table.js"

package compat

type Engine uint8

const (
	Chrome Engine = iota
	Edge
	ES
	Firefox
	IOS
	Node
	Safari
)

func (e Engine) String() string {
	switch e {
	case Chrome:
		return "chrome"
	case Edge:
		return "edge"
	case ES:
		return "es"
	case Firefox:
		return "firefox"
	case IOS:
		return "ios"
	case Node:
		return "node"
	case Safari:
		return "safari"
	}
	return ""
}

type JSFeature uint64

const (
	ArbitraryModuleNamespaceNames JSFeature = 1 << iota
	ArraySpread
	Arrow
	AsyncAwait
	AsyncGenerator
	BigInt
	Class
	ClassField
	ClassPrivateAccessor
	ClassPrivateBrandCheck
	ClassPrivateField
	ClassPrivateMethod
	ClassPrivateStaticAccessor
	ClassPrivateStaticField
	ClassPrivateStaticMethod
	ClassStaticField
	Const
	DefaultArgument
	Destructuring
	DynamicImport
	ExponentOperator
	ExportStarAs
	ForAwait
	ForOf
	Generator
	Hashbang
	ImportAssertions
	ImportMeta
	Let
	LogicalAssignment
	NestedRestBinding
	NewTarget
	NullishCoalescing
	ObjectAccessors
	ObjectExtensions
	ObjectRestSpread
	OptionalCatchBinding
	OptionalChain
	RestArgument
	TemplateLiteral
	TopLevelAwait
	UnicodeEscapes
)

func (features JSFeature) Has(feature JSFeature) bool {
	return (features & feature) != 0
}

var jsTable = map[JSFeature]map[Engine][]int{
	ArbitraryModuleNamespaceNames: {
		Chrome: {90},
		Node:   {16},
	},
	ArraySpread: {
		Chrome:  {46},
		Edge:    {13},
		ES:      {2015},
		Firefox: {36},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	Arrow: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	AsyncAwait: {
		Chrome:  {55},
		Edge:    {15},
		ES:      {2017},
		Firefox: {52},
		IOS:     {11},
		Node:    {7, 6},
		Safari:  {11},
	},
	AsyncGenerator: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	BigInt: {
		Chrome:  {67},
		Edge:    {79},
		ES:      {2020},
		Firefox: {68},
		IOS:     {14},
		Node:    {10, 4},
		Safari:  {14},
	},
	Class: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	ClassField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {69},
		IOS:     {14},
		Node:    {12, 0},
		Safari:  {14},
	},
	ClassPrivateAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		Node:    {14, 6},
	},
	ClassPrivateBrandCheck: {
		Chrome: {91},
	},
	ClassPrivateField: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		Node:    {14, 6},
		Safari:  {14, 1},
	},
	ClassPrivateMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		Node:    {14, 6},
	},
	ClassPrivateStaticAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		Node:    {14, 6},
	},
	ClassPrivateStaticField: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {90},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	ClassPrivateStaticMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		Node:    {14, 6},
	},
	ClassStaticField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {75},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	Const: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	DefaultArgument: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Destructuring: {
		Chrome:  {51},
		Edge:    {18},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	DynamicImport: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2015},
		Firefox: {67},
		IOS:     {11},
		Node:    {13, 2},
		Safari:  {11, 1},
	},
	ExponentOperator: {
		Chrome:  {52},
		Edge:    {14},
		ES:      {2016},
		Firefox: {52},
		IOS:     {10, 3},
		Node:    {7},
		Safari:  {10, 1},
	},
	ExportStarAs: {
		Chrome:  {72},
		Edge:    {79},
		ES:      {2020},
		Firefox: {80},
		Node:    {12},
	},
	ForAwait: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	ForOf: {
		Chrome:  {51},
		Edge:    {15},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	Generator: {
		Chrome:  {50},
		Edge:    {13},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Hashbang: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {67},
		IOS:     {13, 4},
		Node:    {12, 0},
		Safari:  {13, 1},
	},
	ImportAssertions: {
		Chrome: {91},
	},
	ImportMeta: {
		Chrome:  {64},
		Edge:    {79},
		ES:      {2020},
		Firefox: {62},
		IOS:     {12},
		Node:    {10, 4},
		Safari:  {11, 1},
	},
	Let: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	LogicalAssignment: {
		Chrome:  {85},
		Edge:    {85},
		Firefox: {79},
		IOS:     {14},
		Node:    {15, 0},
		Safari:  {14},
	},
	NestedRestBinding: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2016},
		Firefox: {47},
		IOS:     {10, 3},
		Node:    {6},
		Safari:  {10, 1},
	},
	NewTarget: {
		Chrome:  {46},
		Edge:    {14},
		ES:      {2015},
		Firefox: {41},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	NullishCoalescing: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {72},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	ObjectAccessors: {
		Chrome:  {5},
		Edge:    {12},
		ES:      {5},
		Firefox: {2},
		IOS:     {6},
		Node:    {0, 10},
		Safari:  {3, 1},
	},
	ObjectExtensions: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {34},
		IOS:     {10},
		Node:    {4},
		Safari:  {10},
	},
	ObjectRestSpread: {
		ES:      {2018},
		Firefox: {55},
		IOS:     {11, 3},
		Safari:  {11, 1},
	},
	OptionalCatchBinding: {
		Chrome:  {66},
		Edge:    {79},
		ES:      {2019},
		Firefox: {58},
		IOS:     {11, 3},
		Node:    {10, 0},
		Safari:  {11, 1},
	},
	OptionalChain: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {74},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	RestArgument: {
		Chrome:  {47},
		Edge:    {12},
		ES:      {2015},
		Firefox: {43},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	TemplateLiteral: {
		Chrome:  {41},
		Edge:    {13},
		ES:      {2015},
		Firefox: {34},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
	TopLevelAwait: {
		Chrome: {89},
		Node:   {14, 8},
	},
	UnicodeEscapes: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {53},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
}

func isVersionLessThan(a []int, b []int) bool {
	for i := 0; i < len(a) && i < len(b); i++ {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}
	return len(a) < len(b)
}

// Return all features that are not available in at least one environment
func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) {
	for feature, engines := range jsTable {
		for engine, version := range constraints {
			if minVersion, ok := engines[engine]; !ok || isVersionLessThan(version, minVersion) {
				unsupported |= feature
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package discord

import (
	"fmt"
	"strings"

	"github.com/bwmarrin/discordgo"
	"github.com/scbizu/Astral/internal/config"
)

type Bot struct {
	session *discordgo.Session
}

func NewBot() (*Bot, error) {
	bot, err := discordgo.New(config.GetDiscordClientID())
	if err != nil {
		return nil, err
	}
	return &Bot{session: bot}, nil
}

func (b *Bot) ResolveMessage(msgs []string) string {
	return fmt.Sprintf("%s\n\n", strings.Join(msgs, "\n\n"))
}

func (b *Bot) Send(msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageSendEmbed(
		config.DiscordCNSC2ChannelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	); err != nil {
		return err
	}
	return nil
}

func (b *Bot) SendAndReturnID(msg string) (string, error) {
	if err := b.session.Open(); err != nil {
		return "", err
	}
	defer b.session.Close()
	resp, err := b.session.ChannelMessageSendEmbed(
		config.DiscordCNSC2ChannelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	)
	if err != nil {
		return "", err
	}
	return resp.ID, nil
}

func (b *Bot) SendToChannel(channelID string, msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageSendEmbed(
		channelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	); err != nil {
		return err
	}

	return nil
}

func (b *Bot) Edit(msgID string, content string) error {
	return b.editByChannel(config.DiscordCNSC2ChannelID, msgID, content)
}

func (b *Bot) editByChannel(channelID string, msgID string, content string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageEditEmbed(channelID, msgID, &discordgo.MessageEmbed{
		Fields: []*discordgo.MessageEmbedField{
			&discordgo.MessageEmbedField{
				Name:  "Event Closed",
				Value: content,
			},
		}},
	); err != nil {
		return err
	}

	return nil
}
<commit_msg>internal/discord: add lock to fix websocket duplication<commit_after>package discord

import (
	"fmt"
	"strings"
	"sync"

	"github.com/bwmarrin/discordgo"
	"github.com/scbizu/Astral/internal/config"
)

type Bot struct {
	session *discordgo.Session
	sync.Mutex
}

func NewBot() (*Bot, error) {
	bot, err := discordgo.New(config.GetDiscordClientID())
	if err != nil {
		return nil, err
	}
	return &Bot{session: bot}, nil
}

func (b *Bot) ResolveMessage(msgs []string) string {
	return fmt.Sprintf("%s\n\n", strings.Join(msgs, "\n\n"))
}

func (b *Bot) teardown() {
	b.session.Close()
	b.Unlock()
}

func (b *Bot) Send(msg string) error {
	b.Lock()
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.teardown()

	if _, err := b.session.ChannelMessageSendEmbed(
		config.DiscordCNSC2ChannelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	); err != nil {
		return err
	}
	return nil
}

func (b *Bot) SendAndReturnID(msg string) (string, error) {
	b.Lock()
	if err := b.session.Open(); err != nil {
		return "", err
	}
	defer b.teardown()
	resp, err := b.session.ChannelMessageSendEmbed(
		config.DiscordCNSC2ChannelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	)
	if err != nil {
		return "", err
	}
	return resp.ID, nil
}

func (b *Bot) SendToChannel(channelID string, msg string) error {
	b.Lock()
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.teardown()
	if _, err := b.session.ChannelMessageSendEmbed(
		channelID,
		&discordgo.MessageEmbed{
			Fields: []*discordgo.MessageEmbedField{
				&discordgo.MessageEmbedField{
					Name:  "Event Update",
					Value: msg,
				},
			}},
	); err != nil {
		return err
	}

	return nil
}

func (b *Bot) Edit(msgID string, content string) error {
	return b.editByChannel(config.DiscordCNSC2ChannelID, msgID, content)
}

func (b *Bot) editByChannel(channelID string, msgID string, content string) error {
	b.Lock()
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.teardown()
	if _, err := b.session.ChannelMessageEditEmbed(channelID, msgID, &discordgo.MessageEmbed{
		Fields: []*discordgo.MessageEmbedField{
			&discordgo.MessageEmbedField{
				Name:  "Event Closed",
				Value: content,
			},
		}},
	); err != nil {
		return err
	}

	return nil
}
<|endoftext|>