social.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package handlers
  2. import (
  3. "net/http"
  4. "git.linuxforward.com/byom/byom-trends/analysis"
  5. "git.linuxforward.com/byom/byom-trends/common"
  6. "git.linuxforward.com/byom/byom-trends/logger"
  7. "git.linuxforward.com/byom/byom-trends/services/instagram"
  8. "git.linuxforward.com/byom/byom-trends/services/tiktok"
  9. "git.linuxforward.com/byom/byom-trends/services/youtube"
  10. "git.linuxforward.com/byom/byom-trends/store"
  11. "github.com/gin-gonic/gin"
  12. "github.com/google/uuid"
  13. "github.com/sirupsen/logrus"
  14. )
  15. type SocialHandler struct {
  16. store *store.DataStore
  17. analyzer *analysis.TrendAnalyzer
  18. instagramSvc *instagram.Client
  19. tiktokSvc *tiktok.Client
  20. youtubeSvc *youtube.Client
  21. logger *logrus.Entry
  22. }
  23. type ConnectProfileRequest struct {
  24. Platform string `json:"platform" binding:"required,oneof=instagram tiktok youtube"`
  25. Username string `json:"username" binding:"required"`
  26. ProfileURL string `json:"profile_url" binding:"required,url"`
  27. }
  28. func NewSocialHandler(
  29. store *store.DataStore,
  30. instagramSvc *instagram.Client,
  31. tiktokSvc *tiktok.Client,
  32. youtubeSvc *youtube.Client,
  33. ) *SocialHandler {
  34. return &SocialHandler{
  35. store: store,
  36. instagramSvc: instagramSvc,
  37. tiktokSvc: tiktokSvc,
  38. youtubeSvc: youtubeSvc,
  39. logger: logger.NewLogger("social-handler"),
  40. }
  41. }
  42. // ConnectProfile connects a new social media profile
  43. func (h *SocialHandler) ConnectProfile(c *gin.Context) {
  44. var req ConnectProfileRequest
  45. if err := c.ShouldBindJSON(&req); err != nil {
  46. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
  47. return
  48. }
  49. profile := &common.SocialProfile{
  50. ID: uuid.New(),
  51. Platform: req.Platform,
  52. Username: req.Username,
  53. ProfileURL: req.ProfileURL,
  54. }
  55. // Verify profile exists and get initial stats
  56. //var err error
  57. switch req.Platform {
  58. case "instagram":
  59. stats, err := h.instagramSvc.GetProfileStats(req.Username)
  60. if err != nil {
  61. h.logger.WithError(err).Error("failed to get Instagram profile stats")
  62. c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to verify Instagram profile"})
  63. return
  64. }
  65. profile.FollowerCount = stats.FollowerCount
  66. profile.Engagement = stats.Engagement
  67. case "tiktok":
  68. stats, err := h.tiktokSvc.GetProfileStats(req.Username)
  69. if err != nil {
  70. h.logger.WithError(err).Error("failed to get TikTok profile stats")
  71. c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to verify TikTok profile"})
  72. return
  73. }
  74. profile.FollowerCount = stats.FollowerCount
  75. profile.Engagement = stats.Engagement
  76. case "youtube":
  77. stats, err := h.youtubeSvc.GetChannelStats(req.Username)
  78. if err != nil {
  79. h.logger.WithError(err).Error("failed to get YouTube channel stats")
  80. c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to verify YouTube channel"})
  81. return
  82. }
  83. profile.FollowerCount = stats.SubscriberCount
  84. profile.Engagement = stats.Engagement
  85. }
  86. if err := h.store.CreateSocialProfile(c, profile); err != nil {
  87. h.logger.WithError(err).Error("failed to create social profile")
  88. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create social profile"})
  89. return
  90. }
  91. c.JSON(http.StatusCreated, profile)
  92. }
  93. // GetProfileStats retrieves stats for a connected profile
  94. func (h *SocialHandler) GetProfileStats(c *gin.Context) {
  95. platform := c.Param("platform")
  96. username := c.Query("username")
  97. if username == "" {
  98. c.JSON(http.StatusBadRequest, gin.H{"error": "Username is required"})
  99. return
  100. }
  101. var stats interface{}
  102. var err error
  103. switch platform {
  104. case "instagram":
  105. stats, err = h.instagramSvc.GetProfileStats(username)
  106. case "tiktok":
  107. stats, err = h.tiktokSvc.GetProfileStats(username)
  108. case "youtube":
  109. stats, err = h.youtubeSvc.GetChannelStats(username)
  110. default:
  111. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid platform"})
  112. return
  113. }
  114. if err != nil {
  115. h.logger.WithError(err).Error("failed to get profile stats")
  116. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get profile stats"})
  117. return
  118. }
  119. c.JSON(http.StatusOK, stats)
  120. }
  121. // GetProfileEngagement retrieves engagement metrics for a profile
  122. func (h *SocialHandler) GetProfileEngagement(c *gin.Context) {
  123. profileID, err := uuid.Parse(c.Param("id"))
  124. if err != nil {
  125. c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid profile ID"})
  126. return
  127. }
  128. profile, err := h.store.GetSocialProfile(c, profileID)
  129. if err != nil {
  130. h.logger.WithError(err).Error("failed to get social profile")
  131. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get social profile"})
  132. return
  133. }
  134. if profile == nil {
  135. c.JSON(http.StatusNotFound, gin.H{"error": "Profile not found"})
  136. return
  137. }
  138. metrics, err := h.analyzer.AnalyzeEngagement(c, profile)
  139. if err != nil {
  140. h.logger.WithError(err).Error("failed to analyze engagement")
  141. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to analyze engagement"})
  142. return
  143. }
  144. c.JSON(http.StatusOK, metrics)
  145. }