diff --git a/lib/datacache/datacacheinterface/datacacheinterface.go b/lib/datacache/datacacheinterface/datacacheinterface.go index 0e49252..bb7fbd2 100644 --- a/lib/datacache/datacacheinterface/datacacheinterface.go +++ b/lib/datacache/datacacheinterface/datacacheinterface.go @@ -28,6 +28,7 @@ type DataCacheInterface interface { GetPokememeByID(pokememeID int) (*dbmapping.PokememeFull, error) GetPokememeByName(name string) (*dbmapping.PokememeFull, error) DeletePokememeByID(pokememeID int) error + UpdatePokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error) GetLeagueBySymbol(symbol string) (*dbmapping.League, error) diff --git a/lib/datacache/pokememes.go b/lib/datacache/pokememes.go index a87d0a4..d0c1119 100644 --- a/lib/datacache/pokememes.go +++ b/lib/datacache/pokememes.go @@ -5,8 +5,8 @@ package datacache import ( "errors" - "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "sort" + "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "strconv" "strings" "time" @@ -295,3 +295,145 @@ func (dc *DataCache) DeletePokememeByID(pokememeID int) error { dc.fullPokememesMutex.Unlock() return nil } + +// UpdatePokememe updates existing pokememes in database and datacache +func (dc *DataCache) UpdatePokememe(pokememeData map[string]string, pokememeLocations map[string]string, pokememeElements map[string]string) (int, error) { + knownPokememe, err := dc.GetPokememeByName(pokememeData["name"]) + if err != nil { + // This should never happen, but who knows? + return 0, errors.New("This pokememe doesn't exist. We should add it instead") + } + + gradeInt := c.Statistics.GetPoints(pokememeData["grade"]) + attackInt := c.Statistics.GetPoints(pokememeData["attack"]) + hpInt := c.Statistics.GetPoints(pokememeData["hp"]) + mpInt := c.Statistics.GetPoints(pokememeData["mp"]) + defenceInt := attackInt + if pokememeData["defence"] != "" { + defenceInt = c.Statistics.GetPoints(pokememeData["defence"]) + } + priceInt := c.Statistics.GetPoints(pokememeData["price"]) + creatorID := c.Statistics.GetPoints(pokememeData["creator_id"]) + + if !(gradeInt != 0 && attackInt != 0 && hpInt != 0 && mpInt != 0 && defenceInt != 0 && priceInt != 0 && creatorID != 0) { + return 0, errors.New("Some of the required numerical values are empty") + } + + pokememe := knownPokememe.Pokememe + pokememe.Grade = gradeInt + pokememe.Name = pokememeData["name"] + pokememe.Description = pokememeData["description"] + pokememe.Attack = attackInt + pokememe.HP = hpInt + pokememe.MP = mpInt + pokememe.Defence = defenceInt + pokememe.Price = priceInt + if pokememeData["purchaseable"] == "true" { + pokememe.Purchaseable = true + } else { + pokememe.Purchaseable = false + } + pokememe.ImageURL = pokememeData["image"] + pokememe.PlayerID = creatorID + pokememe.CreatedAt = time.Now().UTC() + + locations := []dbmapping.Location{} + elements := []dbmapping.Element{} + + for i := range pokememeLocations { + locationID, err := dc.findLocationIDByName(pokememeLocations[i]) + if err != nil { + return 0, err + } + locations = append(locations, *dc.locations[locationID]) + } + + for i := range pokememeElements { + elementID, err := dc.findElementIDBySymbol(pokememeElements[i]) + if err != nil { + return 0, err + } + elements = append(elements, *dc.elements[elementID]) + } + + // All objects are prepared, let's fill database with it! + c.Log.Debug("Updating existing pokememe...") + _, err = c.Db.NamedExec("UPDATE pokememes SET grade=:grade, name=:name, description=:description, attack=:attack, hp=:hp, mp=:mp, defence=:defence, price=:price, purchaseable=:purchaseable, image_url=:image_url, player_id=:player_id, created_at=:created_at WHERE id=:id", &pokememe) + if err != nil { + return 0, err + } + + // Now we creating locations and elements links + locationsAndElementsFilledSuccessfully := true + c.Log.Debug("Destroying old relations...") + _, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &pokememe) + if err != nil { + c.Log.Error(err.Error()) + locationsAndElementsFilledSuccessfully = false + } + _, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &pokememe) + if err != nil { + c.Log.Error(err.Error()) + locationsAndElementsFilledSuccessfully = false + } + c.Log.Debug("Filling locations...") + for i := range locations { + link := dbmapping.PokememeLocation{} + link.PokememeID = pokememe.ID + link.LocationID = locations[i].ID + link.CreatedAt = time.Now().UTC() + + _, err := c.Db.NamedExec("INSERT INTO pokememes_locations VALUES(NULL, :pokememe_id, :location_id, :created_at)", &link) + if err != nil { + c.Log.Error(err.Error()) + locationsAndElementsFilledSuccessfully = false + } + } + + c.Log.Debug("Filling elements...") + for i := range elements { + link := dbmapping.PokememeElement{} + link.PokememeID = pokememe.ID + link.ElementID = elements[i].ID + link.CreatedAt = time.Now().UTC() + + _, err := c.Db.NamedExec("INSERT INTO pokememes_elements VALUES(NULL, :pokememe_id, :element_id, :created_at)", &link) + if err != nil { + c.Log.Error(err.Error()) + locationsAndElementsFilledSuccessfully = false + } + } + + if !locationsAndElementsFilledSuccessfully { + c.Log.Debug("All fucked up, removing what we have already added...") + // There is something fucked up. In normal state we're should never reach this code + _, err = c.Db.NamedExec("DELETE FROM pokememes_locations WHERE pokememe_id=:id", &pokememe) + if err != nil { + c.Log.Error(err.Error()) + } + _, err = c.Db.NamedExec("DELETE FROM pokememes_elements WHERE pokememe_id=:id", &pokememe) + if err != nil { + c.Log.Error(err.Error()) + } + _, err = c.Db.NamedExec("DELETE FROM pokememes where id=:id", &pokememe) + if err != nil { + c.Log.Error(err.Error()) + } + return 0, errors.New("Failed to add pokememe to database") + } + + fullPokememe := dbmapping.PokememeFull{} + fullPokememe.Pokememe = pokememe + fullPokememe.Locations = locations + fullPokememe.Elements = elements + + // Filling data cache + dc.pokememesMutex.Lock() + dc.fullPokememesMutex.Lock() + dc.pokememes[pokememe.ID] = &pokememe + dc.fullPokememes[pokememe.ID] = &fullPokememe + dc.pokememesMutex.Unlock() + dc.fullPokememesMutex.Unlock() + + return pokememe.ID, nil +} diff --git a/lib/pokedexer/parsers.go b/lib/pokedexer/parsers.go index 7cac67d..e5a1f7f 100644 --- a/lib/pokedexer/parsers.go +++ b/lib/pokedexer/parsers.go @@ -4,9 +4,9 @@ package pokedexer import ( - "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "github.com/go-telegram-bot-api/telegram-bot-api" "regexp" + "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "strconv" "strings" // "time" @@ -136,9 +136,16 @@ func (p *Pokedexer) ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping. _, err = c.DataCache.GetPokememeByName(pokememeData["name"]) if err == nil { - // There is already a pokememe with such name - p.pokememeAddDuplicateMessage(update) - return "fail" + // There is already a pokememe with such name, updating + pokememeID, err := c.DataCache.UpdatePokememe(pokememeData, pokememeLocations, pokememeElements) + if err != nil { + c.Log.Error(err.Error()) + p.pokememeAddFailureMessage(update) + return "fail" + } + + p.pokememeAddDuplicateMessage(update, pokememeID) + return "ok" } newPokememeID, err := c.DataCache.AddPokememe(pokememeData, pokememeLocations, pokememeElements) diff --git a/lib/pokedexer/pokedexer.go b/lib/pokedexer/pokedexer.go index 5f3aa96..060cb78 100644 --- a/lib/pokedexer/pokedexer.go +++ b/lib/pokedexer/pokedexer.go @@ -4,9 +4,9 @@ package pokedexer import ( - "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "github.com/go-telegram-bot-api/telegram-bot-api" "sort" + "source.wtfteam.pro/i2_bot/i2_bot/lib/dbmapping" "strconv" ) @@ -70,10 +70,10 @@ func (p *Pokedexer) pokememeAddSuccessMessage(update *tgbotapi.Update, newPokeme c.Bot.Send(msg) } -func (p *Pokedexer) pokememeAddDuplicateMessage(update *tgbotapi.Update) { - message := "*Мы уже знаем об этом покемеме*\n\n" - message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n\n" - message += "Если у покемема изменились описание или характеристики, напиши @fat0troll для обновления базы." +func (p *Pokedexer) pokememeAddDuplicateMessage(update *tgbotapi.Update, pokememeID int) { + message := "*Покемем успешно обновлён.*\n\n" + message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n" + message += "Посмотреть свежеобновлённого покемема можно командой /pk" + strconv.Itoa(pokememeID) msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) msg.ParseMode = "Markdown"