<commit_before>// LoL Cruncher - A Historical League of Legends Statistics Tracker
// Copyright (C) 2015  <NAME> (1lann) <EMAIL>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package database

import (
	"cruncher/app/models/dataFormat"
	"errors"
	// "fmt"
	r "github.com/dancannon/gorethink"
	"github.com/revel/revel"
	"time"
)

var LastPlayerUpdate = time.Now()

var (
	ErrDisconnected      = errors.New("database: disconnected")
	ErrNoResults         = errors.New("database: no results")
	ErrInsertDiscrepancy = errors.New("database: insert discrepancy")
)

func GetBrowserPlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").OrderBy(r.OrderByOpts{"nn"}).
		Pluck("sn", "r").Run(activeSession)
	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	results := []dataFormat.Player{}
	err = c.All(&results)
	c.Close()
	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err == r.ErrEmptyResult {
		return []dataFormat.Player{}, ErrNoResults
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return results, nil
}

func GetSummonerData(name string, region string) (dataFormat.PlayerData,
	error) {
	if !IsConnected {
		go Connect()
		return dataFormat.PlayerData{}, ErrDisconnected
	}

	name = dataFormat.NormalizeName(name)
	c, err := r.Table("players").
		GetAllByIndex("nr", []string{name, region}).AtIndex(0).
		Merge(func(row r.Term) interface{} {
		return map[string]interface{}{
			"detailed": r.DB("cruncher").Table("detailed").
				GetAllByIndex("ip", row.Field("id")).CoerceTo("array"),
			"basic": r.DB("cruncher").Table("basic").
				GetAllByIndex("ip", row.Field("id")).CoerceTo("array"),
		}
	}).Run(activeSession)

	if isDisconnected(err) {
		return dataFormat.PlayerData{}, ErrDisconnected
	} else if err != nil {
		return dataFormat.PlayerData{}, err
	}

	playerData := dataFormat.PlayerData{}

	err = c.One(&playerData)
	c.Close()
	if isDisconnected(err) {
		return dataFormat.PlayerData{}, ErrDisconnected
	} else if err == r.ErrEmptyResult {
		return dataFormat.PlayerData{}, ErrNoResults
	} else if err != nil {
		return dataFormat.PlayerData{}, err
	}

	return playerData, nil
}

func AddToDetailedPlayer(details dataFormat.DetailedNumberOf) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	resp, err := r.Table("detailed").
		GetAllByIndex("ip", details.InternalPlayerId).Filter(
		map[string]string{
			"p": details.TimePeriod,
			"q": details.Queue,
		}).Update(
		map[string]interface{}{
			"w":  r.Row.Field("w").Add(details.Wins),
			"l":  r.Row.Field("l").Add(details.Losses),
			"t":  r.Row.Field("t").Add(details.TimePlayed),
			"k":  r.Row.Field("k").Add(details.Kills),
			"a":  r.Row.Field("a").Add(details.Assists),
			"d":  r.Row.Field("d").Add(details.Deaths),
			"dk": r.Row.Field("dk").Add(details.DoubleKills),
			"tk": r.Row.Field("tk").Add(details.TripleKills),
			"qk": r.Row.Field("qk").Add(details.QuadraKills),
			"pk": r.Row.Field("pk").Add(details.PentaKills),
			"g":  r.Row.Field("g").Add(details.GoldEarned),
			"m":  r.Row.Field("m").Add(details.MinionsKilled),
			"n":  r.Row.Field("n").Add(details.MonstersKilled),
			"wp": r.Row.Field("wp").Add(details.WardsPlaced),
			"wk": r.Row.Field("wk").Add(details.WardsKilled),
			"b": map[string]interface{}{
				"w": r.Row.Field("b").Field("w").Add(details.Blue.Wins),
				"l": r.Row.Field("b").Field("l").Add(details.Blue.Losses),
			}, "r": map[string]interface{}{
				"w": r.Row.Field("b").Field("w").Add(details.Red.Wins),
				"l": r.Row.Field("b").Field("l").Add(details.Red.Losses),
			},
		}).RunWrite(activeSession)

	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	if resp.Replaced+resp.Unchanged == 0 {
		// Doesn't exist, insert new
		resp, err := r.Table("detailed").Insert(details).RunWrite(activeSession)
		if isDisconnected(err) {
			return ErrDisconnected
		} else if err != nil {
			return err
		} else if resp.Inserted == 0 {
			return ErrInsertDiscrepancy
		}
	}

	return nil
}

func AddToBasicPlayer(details dataFormat.BasicNumberOf) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	resp, err := r.Table("basic").
		GetAllByIndex("ip", details.InternalPlayerId).Filter(
		map[string]string{
			"p": details.TimePeriod,
			"q": details.Queue,
			"c": details.Champion,
		}).Update(
		map[string]interface{}{
			"w":  r.Row.Field("w").Add(details.Wins),
			"l":  r.Row.Field("l").Add(details.Losses),
			"t":  r.Row.Field("t").Add(details.TimePlayed),
			"k":  r.Row.Field("k").Add(details.Kills),
			"a":  r.Row.Field("a").Add(details.Assists),
			"d":  r.Row.Field("d").Add(details.Deaths),
			"g":  r.Row.Field("g").Add(details.GoldEarned),
			"m":  r.Row.Field("m").Add(details.MinionsKilled),
			"n":  r.Row.Field("n").Add(details.MonstersKilled),
			"wp": r.Row.Field("wp").Add(details.WardsPlaced),
		}).RunWrite(activeSession)

	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	if resp.Replaced+resp.Unchanged == 0 {
		// Doesn't exist, insert new
		resp, err := r.Table("basic").Insert(details).RunWrite(activeSession)
		if isDisconnected(err) {
			return ErrDisconnected
		} else if err != nil {
			return err
		} else if resp.Inserted == 0 {
			return ErrInsertDiscrepancy
		}
	}

	return nil
}

func DeletePlayer(player dataFormat.Player) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	_, err := r.Table("players").GetAllByIndex("pi", player.SummonerId).
		Filter(map[string]string{"r": player.Region}).Delete().
		RunWrite(activeSession)
	if err != nil {
		return err
	}

	LastPlayerUpdate = time.Now()

	return nil
}

func CreatePlayer(player dataFormat.Player) (string, error) {
	if !IsConnected {
		go Connect()
		return "", ErrDisconnected
	}

	// Check if player exists already
	c, err := r.Table("players").GetAllByIndex("pi", player.SummonerId).
		Filter(map[string]string{"r": player.Region}).Field("id").
		Run(activeSession)

	if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != nil {
		return "", err
	}

	internalId := ""
	err = c.One(&internalId)
	c.Close()

	LastPlayerUpdate = time.Now()

	if err == nil {
		// Update new summoner name
		revel.WARN.Println("database: updating player summoner name for " +
			internalId)
		_, err := r.Table("players").Get(internalId).Update(
			map[string]string{
				"sn": player.SummonerName,
				"nn": player.NormalizedName,
			}).RunWrite(activeSession)
		if isDisconnected(err) {
			return "", ErrDisconnected
		} else if err != nil {
			return "", err
		}

		return internalId, nil
	} else if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != r.ErrEmptyResult {
		return "", err
	}

	changes, err := r.Table("players").Insert(player).RunWrite(activeSession)
	if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != nil {
		return "", err
	}

	if len(changes.GeneratedKeys) == 0 {
		return "", errors.New("database: missing generated keys")
	}

	return changes.GeneratedKeys[0], nil
}

func GetUpdatePlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").Between(r.MinVal, time.Now(),
		r.BetweenOpts{Index: "nu"}).
		OrderBy(r.OrderByOpts{Index: "nu"}).Pluck("p", "pi", "r", "id").
		Limit(1000).Run(activeSession)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	players := []dataFormat.Player{}
	err = c.All(&players)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return players, nil
}

func GetLongUpdatePlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").Between(r.MinVal, time.Now(),
		r.BetweenOpts{Index: "nl"}).
		OrderBy(r.OrderByOpts{Index: "nl"}).Pluck("p", "pi", "r", "id").
		Limit(1000).Run(activeSession)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	players := []dataFormat.Player{}
	err = c.All(&players)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return players, nil
}

func UpdatePlayerInformation(player dataFormat.Player, data interface{}) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	_, err := r.Table("players").GetAllByIndex("id", player.InternalId).
		Update(data).RunWrite(activeSession)
	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	LastPlayerUpdate = time.Now()

	return nil
}
<commit_msg>Fixed bug not allowing new users<commit_after>// LoL Cruncher - A Historical League of Legends Statistics Tracker
// Copyright (C) 2015  <NAME> (1lann) <EMAIL>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package database

import (
	"cruncher/app/models/dataFormat"
	"errors"
	// "fmt"
	r "github.com/dancannon/gorethink"
	"github.com/revel/revel"
	"strings"
	"time"
)

var LastPlayerUpdate = time.Now()

var (
	ErrDisconnected      = errors.New("database: disconnected")
	ErrNoResults         = errors.New("database: no results")
	ErrInsertDiscrepancy = errors.New("database: insert discrepancy")
)

func GetBrowserPlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").OrderBy(r.OrderByOpts{"nn"}).
		Pluck("sn", "r").Run(activeSession)
	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	results := []dataFormat.Player{}
	err = c.All(&results)
	c.Close()
	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err == r.ErrEmptyResult {
		return []dataFormat.Player{}, ErrNoResults
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return results, nil
}

func GetSummonerData(name string, region string) (dataFormat.PlayerData,
	error) {
	if !IsConnected {
		go Connect()
		return dataFormat.PlayerData{}, ErrDisconnected
	}

	name = dataFormat.NormalizeName(name)
	c, err := r.Table("players").
		GetAllByIndex("nr", []string{name, region}).AtIndex(0).
		Merge(func(row r.Term) interface{} {
		return map[string]interface{}{
			"detailed": r.DB("cruncher").Table("detailed").
				GetAllByIndex("ip", row.Field("id")).CoerceTo("array"),
			"basic": r.DB("cruncher").Table("basic").
				GetAllByIndex("ip", row.Field("id")).CoerceTo("array"),
		}
	}).Run(activeSession)

	if isDisconnected(err) {
		return dataFormat.PlayerData{}, ErrDisconnected
	} else if err != nil {
		return dataFormat.PlayerData{}, err
	}

	playerData := dataFormat.PlayerData{}

	err = c.One(&playerData)
	c.Close()
	if isDisconnected(err) {
		return dataFormat.PlayerData{}, ErrDisconnected
	} else if err == r.ErrEmptyResult {
		return dataFormat.PlayerData{}, ErrNoResults
	} else if strings.Contains(err.Error(), "gorethink: Index out of bounds: 0 in:") {
		return dataFormat.PlayerData{}, ErrNoResults
	} else if err != nil {
		return dataFormat.PlayerData{}, err
	}

	return playerData, nil
}

func AddToDetailedPlayer(details dataFormat.DetailedNumberOf) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	resp, err := r.Table("detailed").
		GetAllByIndex("ip", details.InternalPlayerId).Filter(
		map[string]string{
			"p": details.TimePeriod,
			"q": details.Queue,
		}).Update(
		map[string]interface{}{
			"w":  r.Row.Field("w").Add(details.Wins),
			"l":  r.Row.Field("l").Add(details.Losses),
			"t":  r.Row.Field("t").Add(details.TimePlayed),
			"k":  r.Row.Field("k").Add(details.Kills),
			"a":  r.Row.Field("a").Add(details.Assists),
			"d":  r.Row.Field("d").Add(details.Deaths),
			"dk": r.Row.Field("dk").Add(details.DoubleKills),
			"tk": r.Row.Field("tk").Add(details.TripleKills),
			"qk": r.Row.Field("qk").Add(details.QuadraKills),
			"pk": r.Row.Field("pk").Add(details.PentaKills),
			"g":  r.Row.Field("g").Add(details.GoldEarned),
			"m":  r.Row.Field("m").Add(details.MinionsKilled),
			"n":  r.Row.Field("n").Add(details.MonstersKilled),
			"wp": r.Row.Field("wp").Add(details.WardsPlaced),
			"wk": r.Row.Field("wk").Add(details.WardsKilled),
			"b": map[string]interface{}{
				"w": r.Row.Field("b").Field("w").Add(details.Blue.Wins),
				"l": r.Row.Field("b").Field("l").Add(details.Blue.Losses),
			}, "r": map[string]interface{}{
				"w": r.Row.Field("b").Field("w").Add(details.Red.Wins),
				"l": r.Row.Field("b").Field("l").Add(details.Red.Losses),
			},
		}).RunWrite(activeSession)

	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	if resp.Replaced+resp.Unchanged == 0 {
		// Doesn't exist, insert new
		resp, err := r.Table("detailed").Insert(details).RunWrite(activeSession)
		if isDisconnected(err) {
			return ErrDisconnected
		} else if err != nil {
			return err
		} else if resp.Inserted == 0 {
			return ErrInsertDiscrepancy
		}
	}

	return nil
}

func AddToBasicPlayer(details dataFormat.BasicNumberOf) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	resp, err := r.Table("basic").
		GetAllByIndex("ip", details.InternalPlayerId).Filter(
		map[string]string{
			"p": details.TimePeriod,
			"q": details.Queue,
			"c": details.Champion,
		}).Update(
		map[string]interface{}{
			"w":  r.Row.Field("w").Add(details.Wins),
			"l":  r.Row.Field("l").Add(details.Losses),
			"t":  r.Row.Field("t").Add(details.TimePlayed),
			"k":  r.Row.Field("k").Add(details.Kills),
			"a":  r.Row.Field("a").Add(details.Assists),
			"d":  r.Row.Field("d").Add(details.Deaths),
			"g":  r.Row.Field("g").Add(details.GoldEarned),
			"m":  r.Row.Field("m").Add(details.MinionsKilled),
			"n":  r.Row.Field("n").Add(details.MonstersKilled),
			"wp": r.Row.Field("wp").Add(details.WardsPlaced),
		}).RunWrite(activeSession)

	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	if resp.Replaced+resp.Unchanged == 0 {
		// Doesn't exist, insert new
		resp, err := r.Table("basic").Insert(details).RunWrite(activeSession)
		if isDisconnected(err) {
			return ErrDisconnected
		} else if err != nil {
			return err
		} else if resp.Inserted == 0 {
			return ErrInsertDiscrepancy
		}
	}

	return nil
}

func DeletePlayer(player dataFormat.Player) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	_, err := r.Table("players").GetAllByIndex("pi", player.SummonerId).
		Filter(map[string]string{"r": player.Region}).Delete().
		RunWrite(activeSession)
	if err != nil {
		return err
	}

	LastPlayerUpdate = time.Now()

	return nil
}

func CreatePlayer(player dataFormat.Player) (string, error) {
	if !IsConnected {
		go Connect()
		return "", ErrDisconnected
	}

	// Check if player exists already
	c, err := r.Table("players").GetAllByIndex("pi", player.SummonerId).
		Filter(map[string]string{"r": player.Region}).Field("id").
		Run(activeSession)

	if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != nil {
		return "", err
	}

	internalId := ""
	err = c.One(&internalId)
	c.Close()

	LastPlayerUpdate = time.Now()

	if err == nil {
		// Update new summoner name
		revel.WARN.Println("database: updating player summoner name for " +
			internalId)
		_, err := r.Table("players").Get(internalId).Update(
			map[string]string{
				"sn": player.SummonerName,
				"nn": player.NormalizedName,
			}).RunWrite(activeSession)
		if isDisconnected(err) {
			return "", ErrDisconnected
		} else if err != nil {
			return "", err
		}

		return internalId, nil
	} else if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != r.ErrEmptyResult {
		return "", err
	}

	changes, err := r.Table("players").Insert(player).RunWrite(activeSession)
	if isDisconnected(err) {
		return "", ErrDisconnected
	} else if err != nil {
		return "", err
	}

	if len(changes.GeneratedKeys) == 0 {
		return "", errors.New("database: missing generated keys")
	}

	return changes.GeneratedKeys[0], nil
}

func GetUpdatePlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").Between(r.MinVal, time.Now(),
		r.BetweenOpts{Index: "nu"}).
		OrderBy(r.OrderByOpts{Index: "nu"}).Pluck("p", "pi", "r", "id").
		Limit(1000).Run(activeSession)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	players := []dataFormat.Player{}
	err = c.All(&players)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return players, nil
}

func GetLongUpdatePlayers() ([]dataFormat.Player, error) {
	if !IsConnected {
		go Connect()
		return []dataFormat.Player{}, ErrDisconnected
	}

	c, err := r.Table("players").Between(r.MinVal, time.Now(),
		r.BetweenOpts{Index: "nl"}).
		OrderBy(r.OrderByOpts{Index: "nl"}).Pluck("p", "pi", "r", "id").
		Limit(1000).Run(activeSession)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	players := []dataFormat.Player{}
	err = c.All(&players)

	if isDisconnected(err) {
		return []dataFormat.Player{}, ErrDisconnected
	} else if err != nil {
		return []dataFormat.Player{}, err
	}

	return players, nil
}

func UpdatePlayerInformation(player dataFormat.Player, data interface{}) error {
	if !IsConnected {
		go Connect()
		return ErrDisconnected
	}

	_, err := r.Table("players").GetAllByIndex("id", player.InternalId).
		Update(data).RunWrite(activeSession)
	if isDisconnected(err) {
		return ErrDisconnected
	} else if err != nil {
		return err
	}

	LastPlayerUpdate = time.Now()

	return nil
}

{'fraction_non_alphanumeric': 0.1671045175913048, 'fraction_numerical': 0.0022150105599340647, 'mean_word_length': 4.183978638184246, 'pattern_counts': {'":': 84, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3687766', 'n_tokens_mistral': 7277, 'n_tokens_neox': 6677, 'n_words': 1481}