2019-05-06 01:40:41 +03:00
|
|
|
package services
|
|
|
|
|
|
|
|
import (
|
2021-06-26 13:42:51 +03:00
|
|
|
"fmt"
|
2022-10-04 00:52:22 +03:00
|
|
|
"github.com/duke-git/lancet/v2/convertor"
|
2022-03-25 14:48:56 +03:00
|
|
|
"github.com/duke-git/lancet/v2/datetime"
|
2021-08-07 00:28:03 +03:00
|
|
|
"github.com/emvi/logbuch"
|
2021-04-30 17:20:08 +03:00
|
|
|
"github.com/leandro-lugaresi/hub"
|
2020-09-29 19:55:07 +03:00
|
|
|
"github.com/muety/wakapi/config"
|
2020-03-31 13:22:17 +03:00
|
|
|
"github.com/muety/wakapi/models"
|
2020-11-01 18:56:36 +03:00
|
|
|
"github.com/muety/wakapi/repositories"
|
2020-05-25 22:42:45 +03:00
|
|
|
"github.com/muety/wakapi/utils"
|
2021-01-22 01:19:17 +03:00
|
|
|
"github.com/patrickmn/go-cache"
|
2020-05-24 17:34:32 +03:00
|
|
|
uuid "github.com/satori/go.uuid"
|
2021-01-22 01:19:17 +03:00
|
|
|
"time"
|
2019-05-06 01:40:41 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type UserService struct {
|
2021-08-07 00:28:03 +03:00
|
|
|
config *config.Config
|
|
|
|
cache *cache.Cache
|
|
|
|
eventBus *hub.Hub
|
|
|
|
mailService IMailService
|
|
|
|
repository repositories.IUserRepository
|
2019-05-06 01:40:41 +03:00
|
|
|
}
|
|
|
|
|
2021-08-07 00:28:03 +03:00
|
|
|
func NewUserService(mailService IMailService, userRepo repositories.IUserRepository) *UserService {
|
|
|
|
srv := &UserService{
|
|
|
|
config: config.Get(),
|
|
|
|
eventBus: config.EventBus(),
|
|
|
|
cache: cache.New(1*time.Hour, 2*time.Hour),
|
|
|
|
mailService: mailService,
|
|
|
|
repository: userRepo,
|
2020-05-24 18:32:26 +03:00
|
|
|
}
|
2021-08-07 00:28:03 +03:00
|
|
|
|
|
|
|
sub1 := srv.eventBus.Subscribe(0, config.EventWakatimeFailure)
|
|
|
|
go func(sub *hub.Subscription) {
|
|
|
|
for m := range sub.Receiver {
|
|
|
|
user := m.Fields[config.FieldUser].(*models.User)
|
|
|
|
n := m.Fields[config.FieldPayload].(int)
|
|
|
|
|
|
|
|
logbuch.Warn("resetting wakatime api key for user %s, because of too many failures (%d)", user.ID, n)
|
|
|
|
|
2022-01-21 14:35:05 +03:00
|
|
|
if _, err := srv.SetWakatimeApiCredentials(user, "", ""); err != nil {
|
2021-08-07 00:28:03 +03:00
|
|
|
logbuch.Error("failed to set wakatime api key for user %s", user.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
if user.Email != "" {
|
|
|
|
if err := mailService.SendWakatimeFailureNotification(user, n); err != nil {
|
|
|
|
logbuch.Error("failed to send wakatime failure notification mail to user %s", user.ID)
|
|
|
|
} else {
|
|
|
|
logbuch.Info("sent wakatime connection failure mail to %s", user.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(&sub1)
|
|
|
|
|
|
|
|
return srv
|
2020-05-24 18:32:26 +03:00
|
|
|
}
|
2020-02-20 16:28:55 +03:00
|
|
|
|
2019-05-11 18:49:56 +03:00
|
|
|
func (srv *UserService) GetUserById(userId string) (*models.User, error) {
|
2021-01-22 01:19:17 +03:00
|
|
|
if u, ok := srv.cache.Get(userId); ok {
|
|
|
|
return u.(*models.User), nil
|
|
|
|
}
|
|
|
|
|
2022-12-30 15:14:24 +03:00
|
|
|
u, err := srv.repository.FindOne(models.User{ID: userId})
|
2021-01-22 01:19:17 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-01-02 16:53:21 +03:00
|
|
|
srv.cache.SetDefault(u.ID, u)
|
2021-01-22 01:19:17 +03:00
|
|
|
return u, nil
|
2019-05-06 01:40:41 +03:00
|
|
|
}
|
|
|
|
|
2019-05-11 18:49:56 +03:00
|
|
|
func (srv *UserService) GetUserByKey(key string) (*models.User, error) {
|
2021-01-22 01:19:17 +03:00
|
|
|
if u, ok := srv.cache.Get(key); ok {
|
|
|
|
return u.(*models.User), nil
|
|
|
|
}
|
|
|
|
|
2022-12-30 15:14:24 +03:00
|
|
|
u, err := srv.repository.FindOne(models.User{ApiKey: key})
|
2021-01-22 01:19:17 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-06-26 13:42:51 +03:00
|
|
|
srv.cache.SetDefault(u.ID, u)
|
2021-01-22 01:19:17 +03:00
|
|
|
return u, nil
|
2019-05-06 01:40:41 +03:00
|
|
|
}
|
2019-10-10 00:26:28 +03:00
|
|
|
|
2021-04-05 23:57:57 +03:00
|
|
|
func (srv *UserService) GetUserByEmail(email string) (*models.User, error) {
|
2022-12-30 15:14:24 +03:00
|
|
|
return srv.repository.FindOne(models.User{Email: email})
|
2021-04-05 23:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *UserService) GetUserByResetToken(resetToken string) (*models.User, error) {
|
2022-12-30 15:14:24 +03:00
|
|
|
return srv.repository.FindOne(models.User{ResetToken: resetToken})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *UserService) GetUserByStripeCustomerId(customerId string) (*models.User, error) {
|
|
|
|
return srv.repository.FindOne(models.User{StripeCustomerId: customerId})
|
2021-04-05 23:57:57 +03:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:26:28 +03:00
|
|
|
func (srv *UserService) GetAll() ([]*models.User, error) {
|
2020-11-01 18:56:36 +03:00
|
|
|
return srv.repository.GetAll()
|
2019-10-10 00:26:28 +03:00
|
|
|
}
|
2020-05-24 17:34:32 +03:00
|
|
|
|
2022-10-04 00:52:22 +03:00
|
|
|
func (srv *UserService) GetMany(ids []string) ([]*models.User, error) {
|
|
|
|
return srv.repository.GetMany(ids)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *UserService) GetManyMapped(ids []string) (map[string]*models.User, error) {
|
|
|
|
users, err := srv.repository.GetMany(ids)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return convertor.ToMap[*models.User, string, *models.User](users, func(u *models.User) (string, *models.User) {
|
|
|
|
return u.ID, u
|
|
|
|
}), nil
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:07:14 +03:00
|
|
|
func (srv *UserService) GetAllByReports(reportsEnabled bool) ([]*models.User, error) {
|
|
|
|
return srv.repository.GetAllByReports(reportsEnabled)
|
|
|
|
}
|
|
|
|
|
2022-10-02 01:01:39 +03:00
|
|
|
func (srv *UserService) GetAllByLeaderboard(leaderboardEnabled bool) ([]*models.User, error) {
|
|
|
|
return srv.repository.GetAllByLeaderboard(leaderboardEnabled)
|
|
|
|
}
|
|
|
|
|
2021-06-26 13:42:51 +03:00
|
|
|
func (srv *UserService) GetActive(exact bool) ([]*models.User, error) {
|
2022-03-25 14:48:56 +03:00
|
|
|
minDate := time.Now().AddDate(0, 0, -1*srv.config.App.InactiveDays)
|
2021-06-26 13:42:51 +03:00
|
|
|
if !exact {
|
2022-03-25 14:48:56 +03:00
|
|
|
minDate = datetime.BeginOfHour(minDate)
|
2021-06-26 13:42:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cacheKey := fmt.Sprintf("%s--active", minDate.String())
|
|
|
|
if u, ok := srv.cache.Get(cacheKey); ok {
|
|
|
|
return u.([]*models.User), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
results, err := srv.repository.GetByLastActiveAfter(minDate)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
srv.cache.SetDefault(cacheKey, results)
|
|
|
|
return results, nil
|
2021-02-13 01:06:48 +03:00
|
|
|
}
|
|
|
|
|
2021-02-12 20:49:47 +03:00
|
|
|
func (srv *UserService) Count() (int64, error) {
|
|
|
|
return srv.repository.Count()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *UserService) CreateOrGet(signup *models.Signup, isAdmin bool) (*models.User, bool, error) {
|
2020-05-24 17:34:32 +03:00
|
|
|
u := &models.User{
|
|
|
|
ID: signup.Username,
|
2020-05-25 22:42:45 +03:00
|
|
|
ApiKey: uuid.NewV4().String(),
|
2021-04-25 21:02:45 +03:00
|
|
|
Email: signup.Email,
|
|
|
|
Location: signup.Location,
|
2020-05-25 22:42:45 +03:00
|
|
|
Password: signup.Password,
|
2021-02-12 20:49:47 +03:00
|
|
|
IsAdmin: isAdmin,
|
2020-05-25 22:42:45 +03:00
|
|
|
}
|
|
|
|
|
2023-07-08 20:15:59 +03:00
|
|
|
if hash, err := utils.HashPassword(u.Password, srv.config.Security.PasswordSalt); err != nil {
|
2020-05-25 22:42:45 +03:00
|
|
|
return nil, false, err
|
2020-10-16 17:11:14 +03:00
|
|
|
} else {
|
|
|
|
u.Password = hash
|
2020-05-24 17:34:32 +03:00
|
|
|
}
|
|
|
|
|
2020-11-01 18:56:36 +03:00
|
|
|
return srv.repository.InsertOrGet(u)
|
2020-05-24 17:34:32 +03:00
|
|
|
}
|
2020-05-25 23:24:29 +03:00
|
|
|
|
2020-05-30 23:19:05 +03:00
|
|
|
func (srv *UserService) Update(user *models.User) (*models.User, error) {
|
2023-01-02 16:53:21 +03:00
|
|
|
srv.FlushUserCache(user.ID)
|
2021-04-30 17:20:08 +03:00
|
|
|
srv.notifyUpdate(user)
|
2020-11-01 18:56:36 +03:00
|
|
|
return srv.repository.Update(user)
|
2020-05-30 23:19:05 +03:00
|
|
|
}
|
|
|
|
|
2020-06-07 20:58:06 +03:00
|
|
|
func (srv *UserService) ResetApiKey(user *models.User) (*models.User, error) {
|
2023-01-02 16:53:21 +03:00
|
|
|
srv.FlushUserCache(user.ID)
|
2020-06-07 20:58:06 +03:00
|
|
|
user.ApiKey = uuid.NewV4().String()
|
|
|
|
return srv.Update(user)
|
|
|
|
}
|
|
|
|
|
2022-01-21 14:35:05 +03:00
|
|
|
func (srv *UserService) SetWakatimeApiCredentials(user *models.User, apiKey string, apiUrl string) (*models.User, error) {
|
2023-01-02 16:53:21 +03:00
|
|
|
srv.FlushUserCache(user.ID)
|
2022-01-21 14:35:05 +03:00
|
|
|
|
|
|
|
if apiKey != user.WakatimeApiKey {
|
|
|
|
if u, err := srv.repository.UpdateField(user, "wakatime_api_key", apiKey); err != nil {
|
|
|
|
return u, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if apiUrl != user.WakatimeApiUrl {
|
|
|
|
return srv.repository.UpdateField(user, "wakatime_api_url", apiUrl)
|
|
|
|
}
|
|
|
|
|
|
|
|
return user, nil
|
2021-01-22 01:26:50 +03:00
|
|
|
}
|
|
|
|
|
2021-04-05 23:57:57 +03:00
|
|
|
func (srv *UserService) GenerateResetToken(user *models.User) (*models.User, error) {
|
|
|
|
return srv.repository.UpdateField(user, "reset_token", uuid.NewV4())
|
|
|
|
}
|
|
|
|
|
2021-02-03 00:54:22 +03:00
|
|
|
func (srv *UserService) Delete(user *models.User) error {
|
2023-01-02 16:53:21 +03:00
|
|
|
srv.FlushUserCache(user.ID)
|
2021-04-30 17:20:08 +03:00
|
|
|
|
|
|
|
user.ReportsWeekly = false
|
|
|
|
srv.notifyUpdate(user)
|
2023-04-09 18:29:57 +03:00
|
|
|
srv.notifyDelete(user)
|
2021-04-30 17:20:08 +03:00
|
|
|
|
2021-02-03 00:54:22 +03:00
|
|
|
return srv.repository.Delete(user)
|
|
|
|
}
|
2021-02-07 00:32:03 +03:00
|
|
|
|
|
|
|
func (srv *UserService) FlushCache() {
|
|
|
|
srv.cache.Flush()
|
|
|
|
}
|
2021-04-30 17:20:08 +03:00
|
|
|
|
2023-01-02 16:53:21 +03:00
|
|
|
func (srv *UserService) FlushUserCache(userId string) {
|
|
|
|
srv.cache.Delete(userId)
|
|
|
|
}
|
|
|
|
|
2021-04-30 17:20:08 +03:00
|
|
|
func (srv *UserService) notifyUpdate(user *models.User) {
|
|
|
|
srv.eventBus.Publish(hub.Message{
|
|
|
|
Name: config.EventUserUpdate,
|
|
|
|
Fields: map[string]interface{}{config.FieldPayload: user},
|
|
|
|
})
|
|
|
|
}
|
2023-04-09 18:29:57 +03:00
|
|
|
|
|
|
|
func (srv *UserService) notifyDelete(user *models.User) {
|
|
|
|
srv.eventBus.Publish(hub.Message{
|
|
|
|
Name: config.EventUserDelete,
|
|
|
|
Fields: map[string]interface{}{config.FieldPayload: user},
|
|
|
|
})
|
|
|
|
}
|