* TP-40559 : Incident logs (#227) * TP-40559 : Adding BeforeUpdate and AfterUpdate hook in Incident Entity * TP-40936 - Added deep compare util function * TP-40559 | Added entity and repo for logs * TP-40559 : Added log entry support for incident level updates * Fix zero diff issue * Added lowercase json parameter names * TP-40559 : Added logs for team level updates * Initialize log service * TP-41640 : Added api to fetch logs for particular incident/team * Before create and after create * Convert 2 logs to one on incident creation * Log id populate: * Add populate for team id * Branch update changes * Typo changes * PR REVIEW CHANGES * Nil fix * Fix order issue * TP-43841 | Updating fetch users from conversation to differentiate memeber and others (#245) * Build fix * Added migration script for logs --------- Co-authored-by: Sriram Bhargav <sriram.bhargav@navi.com>
This commit is contained in:
@@ -2,24 +2,24 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"houston/internal/cron"
|
|
||||||
"houston/internal/diagnostic"
|
|
||||||
"houston/internal/processor"
|
|
||||||
"houston/internal/resolver"
|
|
||||||
"houston/model/incident"
|
|
||||||
"houston/model/severity"
|
|
||||||
"houston/model/shedlock"
|
|
||||||
"houston/model/tag"
|
|
||||||
"houston/model/team"
|
|
||||||
"houston/model/user"
|
|
||||||
"houston/pkg/slackbot"
|
|
||||||
|
|
||||||
"github.com/slack-go/slack"
|
"github.com/slack-go/slack"
|
||||||
"github.com/slack-go/slack/slackevents"
|
"github.com/slack-go/slack/slackevents"
|
||||||
"github.com/slack-go/slack/socketmode"
|
"github.com/slack-go/slack/socketmode"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"houston/internal/cron"
|
||||||
|
"houston/internal/diagnostic"
|
||||||
|
"houston/internal/processor"
|
||||||
|
"houston/internal/resolver"
|
||||||
|
"houston/model/incident"
|
||||||
|
"houston/model/log"
|
||||||
|
"houston/model/severity"
|
||||||
|
"houston/model/shedlock"
|
||||||
|
"houston/model/tag"
|
||||||
|
"houston/model/team"
|
||||||
|
"houston/model/user"
|
||||||
|
"houston/pkg/slackbot"
|
||||||
)
|
)
|
||||||
|
|
||||||
type slackHandler struct {
|
type slackHandler struct {
|
||||||
@@ -35,9 +35,10 @@ type slackHandler struct {
|
|||||||
|
|
||||||
func NewSlackHandler(logger *zap.Logger, gormClient *gorm.DB, socketModeClient *socketmode.Client) *slackHandler {
|
func NewSlackHandler(logger *zap.Logger, gormClient *gorm.DB, socketModeClient *socketmode.Client) *slackHandler {
|
||||||
severityService := severity.NewSeverityRepository(logger, gormClient)
|
severityService := severity.NewSeverityRepository(logger, gormClient)
|
||||||
incidentService := incident.NewIncidentRepository(logger, gormClient, severityService)
|
logRepository := log.NewLogRepository(logger, gormClient)
|
||||||
tagService := tag.NewTagRepository(logger, gormClient)
|
tagService := tag.NewTagRepository(logger, gormClient)
|
||||||
teamService := team.NewTeamRepository(logger, gormClient)
|
teamService := team.NewTeamRepository(logger, gormClient, logRepository)
|
||||||
|
incidentService := incident.NewIncidentRepository(logger, gormClient, severityService, logRepository, teamService, socketModeClient)
|
||||||
userService := user.NewUserRepository(logger, gormClient)
|
userService := user.NewUserRepository(logger, gormClient)
|
||||||
shedlockService := shedlock.NewShedlockRepository(logger, gormClient)
|
shedlockService := shedlock.NewShedlockRepository(logger, gormClient)
|
||||||
slackbotClient := slackbot.NewSlackClient(logger, socketModeClient)
|
slackbotClient := slackbot.NewSlackClient(logger, socketModeClient)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ func (s *Server) Handler(houstonGroup *gin.RouterGroup) {
|
|||||||
s.teamHandler(houstonGroup)
|
s.teamHandler(houstonGroup)
|
||||||
s.severityHandler(houstonGroup)
|
s.severityHandler(houstonGroup)
|
||||||
s.incidentHandler(houstonGroup)
|
s.incidentHandler(houstonGroup)
|
||||||
|
s.logHandler(houstonGroup)
|
||||||
s.usersHandler(houstonGroup)
|
s.usersHandler(houstonGroup)
|
||||||
s.filtersHandler(houstonGroup)
|
s.filtersHandler(houstonGroup)
|
||||||
|
|
||||||
@@ -141,6 +142,11 @@ func (s *Server) incidentHandler(houstonGroup *gin.RouterGroup) {
|
|||||||
houstonGroup.GET("/teamIncidents/:teamId", incidentHandler.GetTeamIncidents)
|
houstonGroup.GET("/teamIncidents/:teamId", incidentHandler.GetTeamIncidents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) logHandler(houstonGroup *gin.RouterGroup) {
|
||||||
|
logHandler := service.NewLogService(s.gin, s.logger, s.db)
|
||||||
|
houstonGroup.GET("/logs/:log_type/:id", logHandler.GetLogs)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) usersHandler(houstonGroup *gin.RouterGroup) {
|
func (s *Server) usersHandler(houstonGroup *gin.RouterGroup) {
|
||||||
houstonClient := NewHoustonClient(s.logger)
|
houstonClient := NewHoustonClient(s.logger)
|
||||||
slackClient := slackbot.NewSlackClient(s.logger, houstonClient.socketModeClient)
|
slackClient := slackbot.NewSlackClient(s.logger, houstonClient.socketModeClient)
|
||||||
|
|||||||
@@ -141,3 +141,11 @@ func PostMessageToIncidentChannel(message string, channelId string, client *sock
|
|||||||
_, _, errMessage := client.PostMessage(channelId, msgOption)
|
_, _, errMessage := client.PostMessage(channelId, msgOption)
|
||||||
return errMessage
|
return errMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConvertSliceToMapOfString(input []string) map[string]string {
|
||||||
|
output := make(map[string]string)
|
||||||
|
for _, item := range input {
|
||||||
|
output[item] = item
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|||||||
9
db/migration/000002_add_log_schema.up.sql
Normal file
9
db/migration/000002_add_log_schema.up.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE if not exists log
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
relation_name character varying(255),
|
||||||
|
record_id integer,
|
||||||
|
created_at timestamp without time zone,
|
||||||
|
changes jsonb,
|
||||||
|
user_info jsonb
|
||||||
|
);
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
package incident
|
package incident
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/slack-go/slack/socketmode"
|
||||||
|
"houston/model/log"
|
||||||
"houston/model/severity"
|
"houston/model/severity"
|
||||||
|
"houston/model/team"
|
||||||
|
utils "houston/service/utils"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -15,13 +20,25 @@ type Repository struct {
|
|||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
gormClient *gorm.DB
|
gormClient *gorm.DB
|
||||||
severityRepository *severity.Repository
|
severityRepository *severity.Repository
|
||||||
|
logRepository *log.Repository
|
||||||
|
teamRepository *team.Repository
|
||||||
|
socketModeClient *socketmode.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIncidentRepository(logger *zap.Logger, gormClient *gorm.DB, severityService *severity.Repository) *Repository {
|
var valueBeforeUpdate IncidentEntity
|
||||||
|
var valueAfterUpdate IncidentEntity
|
||||||
|
var valueBeforeCreate IncidentEntity
|
||||||
|
var valueAfterCreate IncidentEntity
|
||||||
|
var differences []utils.Difference
|
||||||
|
|
||||||
|
func NewIncidentRepository(logger *zap.Logger, gormClient *gorm.DB, severityService *severity.Repository, logRepository *log.Repository, teamRepository *team.Repository, socketModeClient *socketmode.Client) *Repository {
|
||||||
return &Repository{
|
return &Repository{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
gormClient: gormClient,
|
gormClient: gormClient,
|
||||||
severityRepository: severityService,
|
severityRepository: severityService,
|
||||||
|
logRepository: logRepository,
|
||||||
|
teamRepository: teamRepository,
|
||||||
|
socketModeClient: socketModeClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,12 +78,141 @@ func (r *Repository) CreateIncidentEntity(request *CreateIncidentDTO) (*Incident
|
|||||||
return incidentEntity, nil
|
return incidentEntity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *IncidentEntity) AfterCreate(tx *gorm.DB) (err error) {
|
||||||
|
println(fmt.Sprintf("AfterUpdate executed at: %v", time.Now()))
|
||||||
|
valueBeforeCreate = IncidentEntity{}
|
||||||
|
valueAfterCreate = IncidentEntity{}
|
||||||
|
if err := tx.First(&valueAfterCreate, i.ID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
println(fmt.Sprintf("incident entity after created is: %s", valueAfterCreate))
|
||||||
|
differences = utils.DeepCompare(valueBeforeCreate, valueAfterCreate)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IncidentEntity) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||||
|
println(fmt.Sprintf("BeforeUpdate executed at: %v", time.Now()))
|
||||||
|
valueBeforeUpdate = IncidentEntity{}
|
||||||
|
if err := tx.First(&valueBeforeUpdate, i.ID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
println(fmt.Sprintf("incident entity before update is: %s", valueBeforeUpdate))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IncidentEntity) AfterUpdate(tx *gorm.DB) (err error) {
|
||||||
|
println(fmt.Sprintf("AfterUpdate executed at: %v", time.Now()))
|
||||||
|
valueAfterUpdate = IncidentEntity{}
|
||||||
|
if err := tx.First(&valueAfterUpdate, i.ID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
println(fmt.Sprintf("incident entity after updated is: %s", valueAfterUpdate))
|
||||||
|
differences = append(differences, utils.DeepCompare(valueBeforeUpdate, valueAfterUpdate)...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) processDiffIds() []byte {
|
||||||
|
var jsonDiff []byte
|
||||||
|
|
||||||
|
for index := range differences {
|
||||||
|
switch differences[index].Attribute {
|
||||||
|
case "Status":
|
||||||
|
if differences[index].From != "" {
|
||||||
|
statusIdString, _ := strconv.Atoi(differences[index].From)
|
||||||
|
statusEntity, _ := r.GetIncidentStatusNameByStatus(uint(statusIdString))
|
||||||
|
if statusEntity != nil {
|
||||||
|
differences[index].From = statusEntity.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statusIdString, _ := strconv.Atoi(differences[index].To)
|
||||||
|
statusEntity, _ := r.GetIncidentStatusNameByStatus(uint(statusIdString))
|
||||||
|
differences[index].To = statusEntity.Name
|
||||||
|
|
||||||
|
case "SeverityId":
|
||||||
|
if differences[index].From != "" {
|
||||||
|
severityIdString, _ := strconv.Atoi(differences[index].From)
|
||||||
|
severityEntity, _ := r.severityRepository.FindSeverityById(uint(severityIdString))
|
||||||
|
if severityEntity != nil {
|
||||||
|
differences[index].From = severityEntity.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
severityIdString, _ := strconv.Atoi(differences[index].To)
|
||||||
|
severityEntity, _ := r.severityRepository.FindSeverityById(uint(severityIdString))
|
||||||
|
differences[index].To = severityEntity.Name
|
||||||
|
|
||||||
|
case "TeamId":
|
||||||
|
if differences[index].From != "" {
|
||||||
|
teamIdString, _ := strconv.Atoi(differences[index].From)
|
||||||
|
teamEntity, _ := r.teamRepository.FindTeamById(uint(teamIdString))
|
||||||
|
if teamEntity != nil {
|
||||||
|
differences[index].From = teamEntity.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
teamIdString, _ := strconv.Atoi(differences[index].To)
|
||||||
|
teamEntity, _ := r.teamRepository.FindTeamById(uint(teamIdString))
|
||||||
|
if teamEntity != nil {
|
||||||
|
differences[index].To = teamEntity.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonDiff, _ = json.Marshal(differences)
|
||||||
|
|
||||||
|
return jsonDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) processUserInfo() ([]byte, error) {
|
||||||
|
user, err := r.socketModeClient.GetUsersInfo(valueAfterUpdate.UpdatedBy)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errorMessage := fmt.Sprintf("failed to get user info from slack for userID: %s", valueAfterUpdate.UpdatedBy)
|
||||||
|
r.logger.Error(errorMessage)
|
||||||
|
return nil, fmt.Errorf("%s. Error: %v", errorMessage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*user) != 0 {
|
||||||
|
userData := (*user)[0]
|
||||||
|
userInfo := log.UserInfo{
|
||||||
|
Id: userData.ID,
|
||||||
|
Email: userData.Profile.Email,
|
||||||
|
Name: userData.Profile.RealName,
|
||||||
|
}
|
||||||
|
return json.Marshal(userInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%s is not a valid user", valueAfterUpdate.UpdatedBy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) captureLogs() {
|
||||||
|
if differences != nil && len(differences) > 0 {
|
||||||
|
jsonUser, _ := r.processUserInfo()
|
||||||
|
|
||||||
|
jsonDiff := r.processDiffIds()
|
||||||
|
|
||||||
|
r.logRepository.CreateLog(
|
||||||
|
&log.LogEntity{
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
RelationName: "incident",
|
||||||
|
RecordId: valueAfterUpdate.ID,
|
||||||
|
UserInfo: jsonUser,
|
||||||
|
Changes: jsonDiff,
|
||||||
|
})
|
||||||
|
|
||||||
|
differences = []utils.Difference{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) UpdateIncident(incidentEntity *IncidentEntity) error {
|
func (r *Repository) UpdateIncident(incidentEntity *IncidentEntity) error {
|
||||||
result := r.gormClient.Updates(incidentEntity)
|
result := r.gormClient.Updates(incidentEntity)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.captureLogs()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
model/log/entity.go
Normal file
24
model/log/entity.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/datatypes"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogEntity struct {
|
||||||
|
CreatedAt time.Time `gorm:"column:created_at"`
|
||||||
|
RelationName string `gorm:"column:relation_name"`
|
||||||
|
RecordId uint `gorm:"column:record_id"`
|
||||||
|
UserInfo datatypes.JSON `gorm:"column:user_info"`
|
||||||
|
Changes datatypes.JSON `gorm:"column:changes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (LogEntity) TableName() string {
|
||||||
|
return "log"
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
48
model/log/log.go
Normal file
48
model/log/log.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Repository struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
gormClient *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogRepository(logger *zap.Logger, gormClient *gorm.DB) *Repository {
|
||||||
|
return &Repository{
|
||||||
|
logger: logger,
|
||||||
|
gormClient: gormClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) CreateLog(logEntity *LogEntity) (*LogEntity, error) {
|
||||||
|
result := r.gormClient.Create(logEntity)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return logEntity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) FetchLogsByRelationNameAndRecordId(relationName string, recordId uint) ([]LogEntity, error) {
|
||||||
|
var query = r.gormClient.Model([]LogEntity{})
|
||||||
|
var logEntity []LogEntity
|
||||||
|
|
||||||
|
if len(relationName) != 0 {
|
||||||
|
query = query.Where("relation_name = ?", relationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.Where("record_id = ?", recordId)
|
||||||
|
|
||||||
|
query = query.Order("created_at ASC")
|
||||||
|
|
||||||
|
result := query.Find(&logEntity)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return logEntity, nil
|
||||||
|
}
|
||||||
@@ -1,19 +1,30 @@
|
|||||||
package team
|
package team
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"houston/model/log"
|
||||||
|
utils "houston/service/utils"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
gormClient *gorm.DB
|
gormClient *gorm.DB
|
||||||
|
logRepository *log.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTeamRepository(logger *zap.Logger, gormClient *gorm.DB) *Repository {
|
var valueBeforeUpdate TeamEntity
|
||||||
|
var valueAfterUpdate TeamEntity
|
||||||
|
var differences []utils.Difference
|
||||||
|
|
||||||
|
func NewTeamRepository(logger *zap.Logger, gormClient *gorm.DB, logRepository *log.Repository) *Repository {
|
||||||
return &Repository{
|
return &Repository{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
gormClient: gormClient,
|
gormClient: gormClient,
|
||||||
|
logRepository: logRepository,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,11 +74,57 @@ func (r *Repository) FindTeamByTeamName(teamName string) (*TeamEntity, error) {
|
|||||||
return &teamEntity, nil
|
return &teamEntity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TeamEntity) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||||
|
println(fmt.Sprintf("BeforeUpdate executed at: %v", time.Now()))
|
||||||
|
valueBeforeUpdate = TeamEntity{}
|
||||||
|
if err := tx.First(&valueBeforeUpdate, t.ID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
println(fmt.Sprintf("team entity before update is: %s", valueBeforeUpdate))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TeamEntity) AfterUpdate(tx *gorm.DB) (err error) {
|
||||||
|
println(fmt.Sprintf("AfterUpdate executed at: %v", time.Now()))
|
||||||
|
valueAfterUpdate = TeamEntity{}
|
||||||
|
if err := tx.First(&valueAfterUpdate, t.ID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
println(fmt.Sprintf("team entity after updated is: %s", valueAfterUpdate))
|
||||||
|
differences = utils.DeepCompare(valueBeforeUpdate, valueAfterUpdate)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) CaptureLogs() {
|
||||||
|
if differences != nil && len(differences) > 0 {
|
||||||
|
jsonDiff, _ := json.Marshal(differences)
|
||||||
|
|
||||||
|
jsonUser, _ := json.Marshal(log.UserInfo{
|
||||||
|
Id: "",
|
||||||
|
Email: valueAfterUpdate.UpdatedBy,
|
||||||
|
Name: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
r.logRepository.CreateLog(
|
||||||
|
&log.LogEntity{
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
RelationName: "team",
|
||||||
|
RecordId: valueAfterUpdate.ID,
|
||||||
|
Changes: jsonDiff,
|
||||||
|
UserInfo: jsonUser,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) UpdateTeam(teamEntity *TeamEntity) error {
|
func (r *Repository) UpdateTeam(teamEntity *TeamEntity) error {
|
||||||
result := r.gormClient.Updates(teamEntity)
|
result := r.gormClient.Updates(teamEntity)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.CaptureLogs()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +133,9 @@ func (r *Repository) UpdateTeamStatus(teamEntity *TeamEntity) error {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.CaptureLogs()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,3 +55,12 @@ func (r *Repository) IsAHoustonUser(nameOrSlackUserId string) (bool, *UserEntity
|
|||||||
}
|
}
|
||||||
return true, &existingUser
|
return true, &existingUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repository) GetHoustonUsersBySlackId(slackUserId []string) (*[]UserEntity, error) {
|
||||||
|
var users []UserEntity
|
||||||
|
result := r.gormClient.Where("slack_user_id IN ?", slackUserId).Find(&users)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return &users, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"houston/model/incident"
|
"houston/model/incident"
|
||||||
|
"houston/model/log"
|
||||||
"houston/model/severity"
|
"houston/model/severity"
|
||||||
"houston/model/team"
|
"houston/model/team"
|
||||||
response "houston/service/response"
|
response "houston/service/response"
|
||||||
@@ -60,8 +61,9 @@ func (f *filterService) GetFilters(c *gin.Context) {
|
|||||||
func (f *filterService) GetEntityRepositories() (
|
func (f *filterService) GetEntityRepositories() (
|
||||||
*incident.Repository, *severity.Repository, *team.Repository) {
|
*incident.Repository, *severity.Repository, *team.Repository) {
|
||||||
severityRepository := severity.NewSeverityRepository(f.logger, f.db)
|
severityRepository := severity.NewSeverityRepository(f.logger, f.db)
|
||||||
incidentRepository := incident.NewIncidentRepository(f.logger, f.db, severityRepository)
|
logRepository := log.NewLogRepository(f.logger, f.db)
|
||||||
teamRespository := team.NewTeamRepository(f.logger, f.db)
|
teamRespository := team.NewTeamRepository(f.logger, f.db, logRepository)
|
||||||
|
incidentRepository := incident.NewIncidentRepository(f.logger, f.db, severityRepository, logRepository, teamRespository, nil)
|
||||||
return incidentRepository, severityRepository, teamRespository
|
return incidentRepository, severityRepository, teamRespository
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"houston/common/util"
|
"houston/common/util"
|
||||||
"houston/internal/processor/action/view"
|
"houston/internal/processor/action/view"
|
||||||
"houston/model/incident"
|
"houston/model/incident"
|
||||||
|
"houston/model/log"
|
||||||
"houston/model/severity"
|
"houston/model/severity"
|
||||||
"houston/model/team"
|
"houston/model/team"
|
||||||
"houston/model/user"
|
"houston/model/user"
|
||||||
@@ -36,11 +37,14 @@ type IncidentServiceV2 struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewIncidentServiceV2(logger *zap.Logger, db *gorm.DB) *IncidentServiceV2 {
|
func NewIncidentServiceV2(logger *zap.Logger, db *gorm.DB) *IncidentServiceV2 {
|
||||||
teamRepository := team.NewTeamRepository(logger, db)
|
logRepository := log.NewLogRepository(logger, db)
|
||||||
|
teamRepository := team.NewTeamRepository(logger, db, logRepository)
|
||||||
severityRepository := severity.NewSeverityRepository(logger, db)
|
severityRepository := severity.NewSeverityRepository(logger, db)
|
||||||
incidentRepository := incident.NewIncidentRepository(logger, db, severityRepository)
|
|
||||||
userRepository := user.NewUserRepository(logger, db)
|
userRepository := user.NewUserRepository(logger, db)
|
||||||
slackService := slack.NewSlackService(logger)
|
slackService := slack.NewSlackService(logger)
|
||||||
|
incidentRepository := incident.NewIncidentRepository(
|
||||||
|
logger, db, severityRepository, logRepository, teamRepository, slackService.SocketModeClient,
|
||||||
|
)
|
||||||
return &IncidentServiceV2{
|
return &IncidentServiceV2{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
db: db,
|
db: db,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"houston/internal/processor/action"
|
"houston/internal/processor/action"
|
||||||
"houston/internal/processor/action/view"
|
"houston/internal/processor/action/view"
|
||||||
"houston/model/incident"
|
"houston/model/incident"
|
||||||
|
"houston/model/log"
|
||||||
"houston/model/severity"
|
"houston/model/severity"
|
||||||
"houston/model/team"
|
"houston/model/team"
|
||||||
"houston/model/user"
|
"houston/model/user"
|
||||||
@@ -45,9 +46,10 @@ type incidentService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewIncidentService(gin *gin.Engine, logger *zap.Logger, db *gorm.DB, socketModeClient *socketmode.Client) *incidentService {
|
func NewIncidentService(gin *gin.Engine, logger *zap.Logger, db *gorm.DB, socketModeClient *socketmode.Client) *incidentService {
|
||||||
teamRepository := team.NewTeamRepository(logger, db)
|
|
||||||
severityRepository := severity.NewSeverityRepository(logger, db)
|
severityRepository := severity.NewSeverityRepository(logger, db)
|
||||||
incidentRepository := incident.NewIncidentRepository(logger, db, severityRepository)
|
logRepository := log.NewLogRepository(logger, db)
|
||||||
|
teamRepository := team.NewTeamRepository(logger, db, logRepository)
|
||||||
|
incidentRepository := incident.NewIncidentRepository(logger, db, severityRepository, logRepository, teamRepository, socketModeClient)
|
||||||
userRepository := user.NewUserRepository(logger, db)
|
userRepository := user.NewUserRepository(logger, db)
|
||||||
messageUpdateAction := action.NewIncidentChannelMessageUpdateAction(
|
messageUpdateAction := action.NewIncidentChannelMessageUpdateAction(
|
||||||
socketModeClient, logger, incidentRepository, teamRepository, severityRepository)
|
socketModeClient, logger, incidentRepository, teamRepository, severityRepository)
|
||||||
|
|||||||
60
service/log_service.go
Normal file
60
service/log_service.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"houston/model/log"
|
||||||
|
service "houston/service/response"
|
||||||
|
common "houston/service/response/common"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type logService struct {
|
||||||
|
gin *gin.Engine
|
||||||
|
logger *zap.Logger
|
||||||
|
db *gorm.DB
|
||||||
|
logRepository *log.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogService(gin *gin.Engine, logger *zap.Logger, db *gorm.DB) *logService {
|
||||||
|
logRepository := log.NewLogRepository(logger, db)
|
||||||
|
return &logService{
|
||||||
|
gin: gin,
|
||||||
|
logger: logger,
|
||||||
|
db: db,
|
||||||
|
logRepository: logRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *logService) GetLogs(c *gin.Context) {
|
||||||
|
logType := c.Param("log_type")
|
||||||
|
id := c.Param("id")
|
||||||
|
|
||||||
|
if len(logType) == 0 {
|
||||||
|
l.logger.Error("Log Type not provided")
|
||||||
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(errors.New("Log type not provided"), http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId, err := strconv.Atoi(id)
|
||||||
|
if err != nil {
|
||||||
|
l.logger.Error("error in converting string to int", zap.String("id", id), zap.Error(err))
|
||||||
|
c.JSON(http.StatusBadGateway, common.ErrorResponse(errors.New("Invalid record id"), http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logs, err := l.logRepository.FetchLogsByRelationNameAndRecordId(logType, uint(recordId))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
l.logger.Error("error in fetching logs by relation name and record", zap.String("id", id), zap.String("relation_name", logType), zap.Error(err))
|
||||||
|
c.JSON(http.StatusBadGateway, common.ErrorResponse(errors.New("Error in fetching logs"), http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logResponse := service.ConvertToLogResponse(logs, logType, uint(recordId))
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, common.SuccessResponse(logResponse, http.StatusOK))
|
||||||
|
}
|
||||||
38
service/response/log_response.go
Normal file
38
service/response/log_response.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/datatypes"
|
||||||
|
"houston/model/log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogResponse struct {
|
||||||
|
RelationName string `json:"relation_name"`
|
||||||
|
RecordId uint `json:"record_id"`
|
||||||
|
Logs []LogEntry `json:"logs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogEntry struct {
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UserInfo datatypes.JSON `json:"user_info"`
|
||||||
|
Changes datatypes.JSON `json:"changes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertToLogResponse(logEnties []log.LogEntity, relationName string, recordId uint) LogResponse {
|
||||||
|
var logs []LogEntry
|
||||||
|
|
||||||
|
for index := range logEnties {
|
||||||
|
logEntry := LogEntry{
|
||||||
|
CreatedAt: logEnties[index].CreatedAt,
|
||||||
|
UserInfo: logEnties[index].UserInfo,
|
||||||
|
Changes: logEnties[index].Changes,
|
||||||
|
}
|
||||||
|
logs = append(logs, logEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LogResponse{
|
||||||
|
RelationName: relationName,
|
||||||
|
RecordId: recordId,
|
||||||
|
Logs: logs,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
|
type ChannelMembersResponse struct {
|
||||||
|
Participants []UserResponse `json:"participants"`
|
||||||
|
Others []UserResponse `json:"others"`
|
||||||
|
}
|
||||||
type UserResponse struct {
|
type UserResponse struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
commonutil "houston/common/util"
|
commonutil "houston/common/util"
|
||||||
|
"houston/model/log"
|
||||||
"houston/model/team"
|
"houston/model/team"
|
||||||
"houston/pkg/slackbot"
|
"houston/pkg/slackbot"
|
||||||
request "houston/service/request"
|
request "houston/service/request"
|
||||||
@@ -40,7 +41,8 @@ func NewTeamService(gin *gin.Engine, logger *zap.Logger, db *gorm.DB, client *sl
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TeamService) AddTeam(c *gin.Context) {
|
func (t *TeamService) AddTeam(c *gin.Context) {
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
minLength := viper.GetInt("TEAM_NAME_MIN_LENGTH")
|
minLength := viper.GetInt("TEAM_NAME_MIN_LENGTH")
|
||||||
maxLength := viper.GetInt("TEAM_NAME_MAX_LENGTH")
|
maxLength := viper.GetInt("TEAM_NAME_MAX_LENGTH")
|
||||||
authResult, _ := t.authService.checkIfManagerOrAdmin(c, "", Admin)
|
authResult, _ := t.authService.checkIfManagerOrAdmin(c, "", Admin)
|
||||||
@@ -165,7 +167,8 @@ func isUserInvalid(userInfo *slack.User, err error) bool {
|
|||||||
func (t *TeamService) GetTeams(c *gin.Context) {
|
func (t *TeamService) GetTeams(c *gin.Context) {
|
||||||
teamId := c.Param("id")
|
teamId := c.Param("id")
|
||||||
|
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
|
|
||||||
if teamId != "" {
|
if teamId != "" {
|
||||||
TeamId, err := strconv.Atoi(teamId)
|
TeamId, err := strconv.Atoi(teamId)
|
||||||
@@ -226,7 +229,8 @@ func (t *TeamService) GetTeams(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TeamService) UpdateTeam(c *gin.Context) {
|
func (t *TeamService) UpdateTeam(c *gin.Context) {
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
userEmail := c.GetHeader("X-User-Email")
|
userEmail := c.GetHeader("X-User-Email")
|
||||||
|
|
||||||
var updateTeamRequest request.UpdateTeamRequest
|
var updateTeamRequest request.UpdateTeamRequest
|
||||||
@@ -333,6 +337,7 @@ func (t *TeamService) UpdateTeam(c *gin.Context) {
|
|||||||
teamEntity.OncallHandle = (*slackUser)[0].ID
|
teamEntity.OncallHandle = (*slackUser)[0].ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
teamEntity.UpdatedBy = userEmail
|
||||||
|
|
||||||
teamRepository.UpdateTeam(teamEntity)
|
teamRepository.UpdateTeam(teamEntity)
|
||||||
c.JSON(http.StatusMultiStatus, common.SuccessResponse("Team updated successfully", http.StatusOK))
|
c.JSON(http.StatusMultiStatus, common.SuccessResponse("Team updated successfully", http.StatusOK))
|
||||||
@@ -343,7 +348,8 @@ func (t *TeamService) RemoveTeamMember(c *gin.Context) {
|
|||||||
teamId := c.Param("id")
|
teamId := c.Param("id")
|
||||||
slackUserId := c.Param("userId")
|
slackUserId := c.Param("userId")
|
||||||
|
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
TeamId, err := utils.ValidateIdParameter(teamId)
|
TeamId, err := utils.ValidateIdParameter(teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.logger.Error(err.Error(), zap.String("teamId", teamId), zap.Error(err))
|
t.logger.Error(err.Error(), zap.String("teamId", teamId), zap.Error(err))
|
||||||
@@ -397,7 +403,8 @@ func (t *TeamService) MakeManager(c *gin.Context) {
|
|||||||
teamId := c.Param("id")
|
teamId := c.Param("id")
|
||||||
teamMemberToMakeManager := c.Param("userId")
|
teamMemberToMakeManager := c.Param("userId")
|
||||||
|
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
|
|
||||||
TeamId, err := utils.ValidateIdParameter(teamId)
|
TeamId, err := utils.ValidateIdParameter(teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -450,7 +457,8 @@ func (t *TeamService) RemoveTeam(c *gin.Context) {
|
|||||||
c.JSON(http.StatusUnauthorized, common.ErrorResponse(errors.New(fmt.Sprintf("%v is not an admin", userEmail)), http.StatusUnauthorized, nil))
|
c.JSON(http.StatusUnauthorized, common.ErrorResponse(errors.New(fmt.Sprintf("%v is not an admin", userEmail)), http.StatusUnauthorized, nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
teamRepository := team.NewTeamRepository(t.logger, t.db)
|
logRepository := log.NewLogRepository(t.logger, t.db)
|
||||||
|
teamRepository := team.NewTeamRepository(t.logger, t.db, logRepository)
|
||||||
TeamId, err := utils.ValidateIdParameter(teamId)
|
TeamId, err := utils.ValidateIdParameter(teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.logger.Error("error reading team id", zap.Error(err))
|
t.logger.Error("error reading team id", zap.Error(err))
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ import (
|
|||||||
"github.com/slack-go/slack/socketmode"
|
"github.com/slack-go/slack/socketmode"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
util "houston/common/util"
|
||||||
"houston/internal/cron"
|
"houston/internal/cron"
|
||||||
|
"houston/model/incident"
|
||||||
|
"houston/model/log"
|
||||||
|
"houston/model/severity"
|
||||||
|
"houston/model/team"
|
||||||
"houston/model/user"
|
"houston/model/user"
|
||||||
"houston/pkg/slackbot"
|
"houston/pkg/slackbot"
|
||||||
service "houston/service/response"
|
service "houston/service/response"
|
||||||
@@ -15,27 +20,36 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type userService struct {
|
type UserService struct {
|
||||||
gin *gin.Engine
|
gin *gin.Engine
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
client *slackbot.Client
|
client *slackbot.Client
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
socketModeClient *socketmode.Client
|
socketModeClient *socketmode.Client
|
||||||
authService *AuthService
|
authService *AuthService
|
||||||
|
userRepository *user.Repository
|
||||||
|
incidentRepository *incident.Repository
|
||||||
|
teamRepository *team.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserService(gin *gin.Engine, logger *zap.Logger, client *slackbot.Client, db *gorm.DB, socketModeClient *socketmode.Client, authService *AuthService) *userService {
|
func NewUserService(gin *gin.Engine, logger *zap.Logger, client *slackbot.Client, db *gorm.DB,
|
||||||
return &userService{
|
socketModeClient *socketmode.Client, authService *AuthService) *UserService {
|
||||||
gin: gin,
|
logRepository := log.NewLogRepository(logger, db)
|
||||||
logger: logger,
|
teamRepository := team.NewTeamRepository(logger, db, logRepository)
|
||||||
client: client,
|
return &UserService{
|
||||||
db: db,
|
gin: gin,
|
||||||
socketModeClient: socketModeClient,
|
logger: logger,
|
||||||
authService: authService,
|
client: client,
|
||||||
|
db: db,
|
||||||
|
socketModeClient: socketModeClient,
|
||||||
|
authService: authService,
|
||||||
|
userRepository: user.NewUserRepository(logger, db),
|
||||||
|
incidentRepository: incident.NewIncidentRepository(logger, db, severity.NewSeverityRepository(logger, db), logRepository, teamRepository, socketModeClient),
|
||||||
|
teamRepository: teamRepository,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userService) GetUserInfo(c *gin.Context) {
|
func (u *UserService) GetUserInfo(c *gin.Context) {
|
||||||
userId := c.Param("id")
|
userId := c.Param("id")
|
||||||
|
|
||||||
users, err := u.client.GetUsersInfo(userId)
|
users, err := u.client.GetUsersInfo(userId)
|
||||||
@@ -53,37 +67,61 @@ func (u *userService) GetUserInfo(c *gin.Context) {
|
|||||||
}, http.StatusOK))
|
}, http.StatusOK))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userService) GetUsersInConversation(c *gin.Context) {
|
func (u *UserService) GetUsersInConversation(c *gin.Context) {
|
||||||
channelId := c.Query("channel_id")
|
channelId := c.Query("channel_id")
|
||||||
|
incidentEntity, err := u.incidentRepository.FindIncidentByChannelId(channelId)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error("error in getting incident by channel id", zap.String("channelId", channelId), zap.Error(err))
|
||||||
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if incidentEntity == nil {
|
||||||
|
err := errors.New(fmt.Sprintf("incident with channel id %v not found", channelId))
|
||||||
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
teamEntity, err := u.teamRepository.FindTeamById(incidentEntity.TeamId)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error(fmt.Sprintf("error getting team info for team with id %v", incidentEntity.TeamId), zap.Error(err))
|
||||||
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
users, err := u.client.GetUsersInConversation(channelId)
|
users, err := u.client.GetUsersInConversation(channelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.logger.Error("error in getting users from conversation", zap.String("channelId", channelId), zap.Error(err))
|
u.logger.Error(fmt.Sprintf("error in getting users from channel %v", channelId), zap.Error(err))
|
||||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
usersInfo, err := u.client.GetUsersInfo(users...)
|
usersInfo, err := u.client.GetUsersInfo(users...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.logger.Error("error in getting users info", zap.Any("userIds", users), zap.Error(err))
|
u.logger.Error("error in getting users info", zap.Error(err))
|
||||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
usersData := *usersInfo
|
usersData := *usersInfo
|
||||||
var usersResponses []service.UserResponse = []service.UserResponse{}
|
teamMembers := util.ConvertSliceToMapOfString(teamEntity.SlackUserIds)
|
||||||
|
var participants []service.UserResponse
|
||||||
for userInfo := range usersData {
|
var others []service.UserResponse
|
||||||
usersResponses = append(usersResponses, service.UserResponse{
|
for userIndex := range usersData {
|
||||||
Id: usersData[userInfo].ID,
|
userInfo := service.UserResponse{
|
||||||
Name: usersData[userInfo].Profile.RealName,
|
Id: usersData[userIndex].ID,
|
||||||
Email: usersData[userInfo].Profile.Email,
|
Name: usersData[userIndex].Profile.RealName,
|
||||||
Image: usersData[userInfo].Profile.Image32,
|
Email: usersData[userIndex].Profile.Email,
|
||||||
})
|
Image: usersData[userIndex].Profile.Image32,
|
||||||
|
}
|
||||||
|
if teamMembers[usersData[userIndex].ID] != "" {
|
||||||
|
participants = append(participants, userInfo)
|
||||||
|
} else {
|
||||||
|
others = append(others, userInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
c.JSON(http.StatusOK, common.SuccessResponse(service.ChannelMembersResponse{
|
||||||
c.JSON(http.StatusOK, common.SuccessResponse(usersResponses, http.StatusOK))
|
Participants: participants,
|
||||||
|
Others: others,
|
||||||
|
}, http.StatusOK))
|
||||||
}
|
}
|
||||||
func (u *userService) UpdateHoustonUsers(c *gin.Context) {
|
func (u *UserService) UpdateHoustonUsers(c *gin.Context) {
|
||||||
|
|
||||||
userEmail := c.GetHeader("X-User-Email")
|
userEmail := c.GetHeader("X-User-Email")
|
||||||
authResult, _ := u.authService.checkIfManagerOrAdmin(c, "", Admin, Manager)
|
authResult, _ := u.authService.checkIfManagerOrAdmin(c, "", Admin, Manager)
|
||||||
|
|||||||
40
service/utils/deep_compare.go
Normal file
40
service/utils/deep_compare.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Difference struct {
|
||||||
|
Attribute string `json:"attribute"`
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeepCompare(before, after interface{}) []Difference {
|
||||||
|
var differences []Difference
|
||||||
|
|
||||||
|
valBefore := reflect.ValueOf(before)
|
||||||
|
valAfter := reflect.ValueOf(after)
|
||||||
|
|
||||||
|
if valBefore.Type() != valAfter.Type() {
|
||||||
|
return append(differences, Difference{"TypeMismatch", valBefore.Type().String(), valAfter.Type().String()})
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := 0; index < valBefore.NumField(); index++ {
|
||||||
|
fieldType := valBefore.Type().Field(index)
|
||||||
|
fieldName := fieldType.Name
|
||||||
|
fieldBefore := valBefore.Field(index)
|
||||||
|
fieldAfter := valAfter.Field(index)
|
||||||
|
|
||||||
|
if fieldName != "Model" && !reflect.DeepEqual(fieldBefore.Interface(), fieldAfter.Interface()) {
|
||||||
|
differences = append(differences, Difference{
|
||||||
|
Attribute: fieldName,
|
||||||
|
From: fmt.Sprintf("%v", fieldBefore.Interface()),
|
||||||
|
To: fmt.Sprintf("%v", fieldAfter.Interface()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return differences
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user