1
0
mirror of synced 2024-11-21 20:16:02 +03:00

add user struct and migrate, check activity connection, upload avatar to s3

This commit is contained in:
DmitryZagorulko 2018-06-04 16:48:04 +03:00
parent 80f4e16fc2
commit 3bb3d9bd4f
9 changed files with 203 additions and 25 deletions

View File

@ -4,8 +4,8 @@ import (
"io/ioutil"
"path/filepath"
logging "github.com/op/go-logging"
yaml "gopkg.in/yaml.v2"
"github.com/op/go-logging"
"gopkg.in/yaml.v2"
)
// TransportConfig struct
@ -15,6 +15,17 @@ type TransportConfig struct {
SentryDSN string `yaml:"sentry_dsn"`
HTTPServer HTTPServerConfig `yaml:"http_server"`
Debug bool `yaml:"debug"`
UpdateTime int `yaml:"update_time"`
ConfigAWS ConfigAWS `yaml:"config_aws"`
}
// ConfigAWS struct
type ConfigAWS struct {
AccessKeyID string `yaml:"access_key_id"`
SecretAccessKey string `yaml:"secret_access_key"`
Region string `yaml:"region"`
Bucket string `yaml:"bucket"`
ContentType string `yaml:"content_type"`
}
// DatabaseConfig struct

View File

@ -10,3 +10,12 @@ sentry_dsn: ~
log_level: 5
debug: false
update_time: 24
config_aws:
access_key_id: ~
secret_access_key: ~
region: ~
bucket: ~
content_type: image/jpeg

View File

@ -35,10 +35,18 @@ func NewDb(config *TransportConfig) *Orm {
setCreatedAt := func(scope *gorm.Scope) {
if scope.HasColumn("CreatedAt") {
scope.SetColumn("CreatedAt", time.Now())
scope.SetColumn("UpdatedAt", time.Now())
}
}
setUpdatedAt := func(scope *gorm.Scope) {
if scope.HasColumn("UpdatedAt") {
scope.SetColumn("UpdatedAt", time.Now())
}
}
db.Callback().Create().Replace("gorm:update_time_stamp", setCreatedAt)
db.Callback().Update().Register("update_time_stamp", setUpdatedAt)
return &Orm{
DB: db,

View File

@ -0,0 +1 @@
drop table user_tg;

View File

@ -0,0 +1,13 @@
create table user_tg
(
id serial not null
constraint user_tg_pkey
primary key,
external_id integer not null,
user_photo varchar(255),
user_photo_id varchar(100),
created_at timestamp with time zone,
updated_at timestamp with time zone,
constraint user_tg_key unique(external_id, user_photo, user_photo_id)
);

View File

@ -28,5 +28,15 @@ type Bot struct {
Active bool `json:"active,omitempty"`
}
// UserTG model
type UserTG struct {
ID int `gorm:"primary_key"`
ExternalID int `gorm:"external_id;not null;unique"`
UserPhotoURL string `gorm:"user_photo type:varchar(255);unique"`
UserPhotoID string `gorm:"user_photo_id type:varchar(100);unique"`
CreatedAt time.Time
UpdatedAt time.Time
}
//Bots list
type Bots []Bot

View File

@ -78,3 +78,14 @@ func getConnectionById(id int) *Connection {
return &connection
}
func (u *UserTG) saveUser() error {
return orm.DB.Save(u).Error
}
func getUserByExternalID(eid int) *UserTG {
user := UserTG{ExternalID: eid}
orm.DB.First(&user)
return &user
}

View File

@ -152,7 +152,7 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
return
}
bot, err := GetBotInfo(b.Token)
bot, err := tgbotapi.NewBotAPI(b.Token)
if err != nil {
logger.Error(b.Token, err.Error())
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "incorrect_token"}), http.StatusBadRequest)
@ -278,8 +278,8 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
err = b.setBotActivity()
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(b.ID, err.Error())
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_save"}), http.StatusInternalServerError)
logger.Error(b.ID, err.Error())
return
}
@ -530,7 +530,7 @@ func activityHandler(w http.ResponseWriter, r *http.Request) {
}
c := getConnection(rec.ClientId)
c.Active = rec.Activity.Active
c.Active = rec.Activity.Active && !rec.Activity.Freeze
if err := c.setConnectionActivity(); err != nil {
raven.CaptureErrorAndWait(err, nil)

View File

@ -2,11 +2,18 @@ package main
import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"strconv"
"time"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/getsentry/raven-go"
"github.com/go-telegram-bot-api/telegram-bot-api"
"github.com/retailcrm/mg-transport-api-client-go/v1"
@ -17,15 +24,6 @@ func setTransportRoutes() {
http.HandleFunc("/webhook/", mgWebhookHandler)
}
// GetBotInfo function
func GetBotInfo(token string) (*tgbotapi.BotAPI, error) {
bot, err := tgbotapi.NewBotAPI(token)
if err != nil {
return nil, err
}
return bot, nil
}
// GetBotName function
func GetBotName(bot *tgbotapi.BotAPI) string {
return bot.Self.FirstName
@ -40,21 +38,15 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
return
}
if b.ID == 0 {
logger.Error(token, "missing")
w.WriteHeader(http.StatusBadRequest)
return
}
if !b.Active {
logger.Error(token, "deactivated")
if b.ID == 0 || !b.Active {
logger.Error(token, "missing or deactivated")
w.WriteHeader(http.StatusBadRequest)
return
}
c := getConnectionById(b.ConnectionID)
if c.MGURL == "" || c.MGToken == "" {
logger.Error(token, "MGURL or MGToken is empty")
if !c.Active {
logger.Error(c.ClientID, " connection deativated")
w.WriteHeader(http.StatusBadRequest)
return
}
@ -64,8 +56,8 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
w.WriteHeader(http.StatusInternalServerError)
logger.Error(token, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -81,6 +73,44 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
return
}
user := getUserByExternalID(update.Message.From.ID)
if time.Now().After(user.UpdatedAt.Add(time.Hour*time.Duration(config.UpdateTime))) || user.ID == 0 {
fileID, fileURL, err := getFileIDAndURL(b.Token, update.Message.From.ID)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if fileID != user.UserPhotoID && fileURL != "" {
picURL, err := UploadUserAvatar(fileURL)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
user.UserPhotoID = fileID
user.UserPhotoURL = picURL
}
if user.ExternalID == 0 {
user.ExternalID = update.Message.From.ID
}
err = user.saveUser()
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
var client = v1.New(c.MGURL, c.MGToken)
if update.Message != nil {
@ -98,6 +128,7 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
ExternalID: strconv.Itoa(update.Message.From.ID),
Nickname: update.Message.From.UserName,
Firstname: update.Message.From.FirstName,
Avatar: user.UserPhotoURL,
Lastname: update.Message.From.LastName,
Language: update.Message.From.LanguageCode,
},
@ -154,6 +185,7 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -166,6 +198,7 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -175,11 +208,23 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
b := getBotByChannel(msg.Data.ChannelID)
if b.ID == 0 {
logger.Error(msg.Data.ChannelID, "missing")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Bot missing"))
return
}
if !b.Active {
logger.Error(msg.Data.ChannelID, "deactivated")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Bot deactivated"))
return
}
c := getConnectionById(b.ConnectionID)
if !c.Active {
logger.Error(c.ClientID, " connection deativated")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Connection deactivated"))
return
}
@ -187,6 +232,7 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -252,3 +298,72 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Message deleted"))
}
}
func getFileIDAndURL(token string, userID int) (fileID, fileURL string, err error) {
bot, err := tgbotapi.NewBotAPI(token)
if err != nil {
return
}
bot.Debug = config.Debug
res, err := bot.GetUserProfilePhotos(
tgbotapi.UserProfilePhotosConfig{
UserID: userID,
Limit: 1,
},
)
if err != nil {
return
}
if len(res.Photos) > 0 {
fileID = res.Photos[0][len(res.Photos[0])-1].FileID
fileURL, err = bot.GetFileDirectURL(fileID)
if err != nil {
return
}
return
}
return
}
func UploadUserAvatar(url string) (picURLs3 string, err error) {
s3Config := &aws.Config{
Credentials: credentials.NewStaticCredentials(
config.ConfigAWS.AccessKeyID,
config.ConfigAWS.SecretAccessKey,
""),
Region: aws.String(config.ConfigAWS.Region),
}
s := session.Must(session.NewSession(s3Config))
uploader := s3manager.NewUploader(s)
resp, err := http.Get(url)
if err != nil {
return
}
if resp.StatusCode >= http.StatusBadRequest {
return "", errors.New(fmt.Sprintf("get: %v code: %v", url, resp.StatusCode))
}
defer resp.Body.Close()
result, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(config.ConfigAWS.Bucket),
Key: aws.String(fmt.Sprintf("%v.jpg", GenerateToken())),
Body: resp.Body,
ContentType: aws.String(config.ConfigAWS.ContentType),
ACL: aws.String("public-read"),
})
if err != nil {
return
}
picURLs3 = result.Location
return
}