e13545c5f1
modified: begushiybashkir/bbvue/src/stores/auth.js modified: begushiybashkir/bbvue/src/views/Profile.vue modified: begushiybashkir/bbvue/src/views/ProfileEdit.vue modified: serv_nginx/api_bb/go.mod modified: serv_nginx/api_bb/go.sum modified: serv_nginx/api_bb/internal/handlers/auth.go new file: serv_nginx/api_bb/internal/handlers/avatar.go modified: serv_nginx/api_bb/internal/handlers/news_handler.go modified: serv_nginx/api_bb/internal/handlers/user.go modified: serv_nginx/api_bb/internal/models/user.go modified: serv_nginx/api_bb/internal/repository/user_repository.go modified: serv_nginx/api_bb/internal/routes/routes.go modified: serv_nginx/api_bb/internal/service/auth_service.go new file: serv_nginx/api_bb/internal/service/avatar_service.go modified: serv_nginx/api_bb/internal/service/news_service.go modified: serv_nginx/api_bb/internal/service/user_service.go modified: serv_nginx/api_bb/pkg/logger/interface.go new file: serv_nginx/api_bb/pkg/logger/route_logger.go add structure fix, page, path, routes, component, authStore for upload, renew and delete avatar
246 lines
6.4 KiB
Go
246 lines
6.4 KiB
Go
package service
|
|
|
|
import (
|
|
"api_bb/internal/models"
|
|
"api_bb/internal/repository"
|
|
"api_bb/pkg/logger"
|
|
"errors"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type NewsService interface {
|
|
CreateNews(req models.CreateNewsRequest, authorID uint) (*models.NewsResponse, error)
|
|
GetNewsByID(id uint) (*models.NewsResponse, error)
|
|
GetAllNews(limit, offset int, category string) ([]models.NewsResponse, int64, error)
|
|
UpdateNews(id uint, req models.UpdateNewsRequest, userID uint) (*models.NewsResponse, error)
|
|
DeleteNews(id uint, userID uint) error
|
|
IncrementViews(id uint) error
|
|
CreateComment(newsID uint, req models.CreateCommentRequest, authorID uint) (*models.CommentResponse, error)
|
|
GetCommentsByNewsID(newsID uint) ([]models.CommentResponse, error)
|
|
DeleteComment(commentID, userID uint) error
|
|
GetUserNews(userID uint, limit, offset int) ([]models.NewsResponse, int64, error)
|
|
}
|
|
|
|
type newsService struct {
|
|
newsRepo repository.NewsRepository
|
|
commentRepo repository.CommentRepository
|
|
logger logger.LoggerInterface
|
|
}
|
|
|
|
func NewNewsService(newsRepo repository.NewsRepository, commentRepo repository.CommentRepository, log logger.LoggerInterface) NewsService {
|
|
|
|
serviceLogger := log.With(zap.String("service", "news"))
|
|
|
|
return &newsService{
|
|
newsRepo: newsRepo,
|
|
commentRepo: commentRepo,
|
|
logger: serviceLogger,
|
|
}
|
|
}
|
|
|
|
func (s *newsService) CreateNews(req models.CreateNewsRequest, authorID uint) (*models.NewsResponse, error) {
|
|
news := &models.News{
|
|
Title: req.Title,
|
|
Excerpt: req.Excerpt,
|
|
Content: req.Content,
|
|
Image: req.Image,
|
|
Category: req.Category,
|
|
AuthorID: authorID,
|
|
}
|
|
|
|
if err := s.newsRepo.Create(news); err != nil {
|
|
s.logger.Error("Failed to create news", zap.Error(err))
|
|
return nil, errors.New("failed to create news")
|
|
}
|
|
|
|
// Получаем созданную новость с автором
|
|
createdNews, err := s.newsRepo.GetByID(news.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.toNewsResponse(createdNews), nil
|
|
}
|
|
|
|
func (s *newsService) GetNewsByID(id uint) (*models.NewsResponse, error) {
|
|
news, err := s.newsRepo.GetByID(id)
|
|
if err != nil {
|
|
return nil, errors.New("news not found")
|
|
}
|
|
|
|
// Увеличиваем счетчик просмотров
|
|
go s.newsRepo.IncrementViews(id)
|
|
|
|
return s.toNewsResponse(news), nil
|
|
}
|
|
|
|
func (s *newsService) GetAllNews(limit, offset int, category string) ([]models.NewsResponse, int64, error) {
|
|
news, total, err := s.newsRepo.GetAll(limit, offset, category)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
responses := make([]models.NewsResponse, len(news))
|
|
for i, n := range news {
|
|
responses[i] = *s.toNewsResponse(&n)
|
|
}
|
|
|
|
return responses, total, nil
|
|
}
|
|
|
|
func (s *newsService) UpdateNews(id uint, req models.UpdateNewsRequest, userID uint) (*models.NewsResponse, error) {
|
|
news, err := s.newsRepo.GetByID(id)
|
|
if err != nil {
|
|
return nil, errors.New("news not found")
|
|
}
|
|
|
|
// Проверяем права доступа
|
|
if news.AuthorID != userID {
|
|
return nil, errors.New("access denied")
|
|
}
|
|
|
|
// Обновляем поля
|
|
if req.Title != "" {
|
|
news.Title = req.Title
|
|
}
|
|
if req.Excerpt != "" {
|
|
news.Excerpt = req.Excerpt
|
|
}
|
|
if req.Content != "" {
|
|
news.Content = req.Content
|
|
}
|
|
if req.Image != "" {
|
|
news.Image = req.Image
|
|
}
|
|
if req.Category != "" {
|
|
news.Category = req.Category
|
|
}
|
|
|
|
if err := s.newsRepo.Update(news); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.toNewsResponse(news), nil
|
|
}
|
|
|
|
func (s *newsService) DeleteNews(id uint, userID uint) error {
|
|
news, err := s.newsRepo.GetByID(id)
|
|
if err != nil {
|
|
return errors.New("news not found")
|
|
}
|
|
|
|
// Проверяем права доступа
|
|
if news.AuthorID != userID {
|
|
return errors.New("access denied")
|
|
}
|
|
|
|
return s.newsRepo.Delete(id)
|
|
}
|
|
|
|
func (s *newsService) IncrementViews(id uint) error {
|
|
return s.newsRepo.IncrementViews(id)
|
|
}
|
|
|
|
func (s *newsService) CreateComment(newsID uint, req models.CreateCommentRequest, authorID uint) (*models.CommentResponse, error) {
|
|
// Проверяем существование новости
|
|
_, err := s.newsRepo.GetByID(newsID)
|
|
if err != nil {
|
|
return nil, errors.New("news not found")
|
|
}
|
|
|
|
comment := &models.Comment{
|
|
Content: req.Content,
|
|
NewsID: newsID,
|
|
AuthorID: authorID,
|
|
}
|
|
|
|
if err := s.commentRepo.Create(comment); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Получаем созданный комментарий с автором
|
|
createdComment, err := s.commentRepo.GetByID(comment.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.toCommentResponse(createdComment), nil
|
|
}
|
|
|
|
func (s *newsService) GetCommentsByNewsID(newsID uint) ([]models.CommentResponse, error) {
|
|
comments, err := s.commentRepo.GetByNewsID(newsID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
responses := make([]models.CommentResponse, len(comments))
|
|
for i, c := range comments {
|
|
responses[i] = *s.toCommentResponse(&c)
|
|
}
|
|
|
|
return responses, nil
|
|
}
|
|
|
|
func (s *newsService) DeleteComment(commentID, userID uint) error {
|
|
comment, err := s.commentRepo.GetByID(commentID)
|
|
if err != nil {
|
|
return errors.New("comment not found")
|
|
}
|
|
|
|
// Проверяем права доступа
|
|
if comment.AuthorID != userID {
|
|
return errors.New("access denied")
|
|
}
|
|
|
|
return s.commentRepo.Delete(commentID)
|
|
}
|
|
|
|
func (s *newsService) GetUserNews(userID uint, limit, offset int) ([]models.NewsResponse, int64, error) {
|
|
news, total, err := s.newsRepo.GetByAuthor(userID, limit, offset)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
responses := make([]models.NewsResponse, len(news))
|
|
for i, n := range news {
|
|
responses[i] = *s.toNewsResponse(&n)
|
|
}
|
|
|
|
return responses, total, nil
|
|
}
|
|
|
|
// Вспомогательные методы для преобразования
|
|
func (s *newsService) toNewsResponse(news *models.News) *models.NewsResponse {
|
|
return &models.NewsResponse{
|
|
ID: news.ID,
|
|
CreatedAt: news.CreatedAt,
|
|
UpdatedAt: news.UpdatedAt,
|
|
Title: news.Title,
|
|
Excerpt: news.Excerpt,
|
|
Content: news.Content,
|
|
Image: news.Image,
|
|
Category: news.Category,
|
|
Views: news.Views,
|
|
Author: models.AuthorInfo{
|
|
ID: news.Author.ID,
|
|
FirstName: news.Author.FirstName,
|
|
LastName: news.Author.LastName,
|
|
},
|
|
Comments: len(news.Comments),
|
|
}
|
|
}
|
|
|
|
func (s *newsService) toCommentResponse(comment *models.Comment) *models.CommentResponse {
|
|
return &models.CommentResponse{
|
|
ID: comment.ID,
|
|
CreatedAt: comment.CreatedAt,
|
|
Content: comment.Content,
|
|
Author: models.AuthorInfo{
|
|
ID: comment.Author.ID,
|
|
FirstName: comment.Author.FirstName,
|
|
LastName: comment.Author.LastName,
|
|
},
|
|
}
|
|
}
|