Skip to content

Commit

Permalink
yes docs, no categories yet
Browse files Browse the repository at this point in the history
  • Loading branch information
pai0id committed Jul 12, 2024
1 parent 7419eb8 commit 6532077
Show file tree
Hide file tree
Showing 16 changed files with 524 additions and 211 deletions.
8 changes: 4 additions & 4 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ func main() {
eventsService := app.NewEventsService(appStorage)
membersService := app.NewMembersService(appStorage)
guardService := app.NewGuardService(appStorage)
// documentsService := app.NewDocumentsService(appStorage, os.Getenv("DOCUMENT_BUCKET"))
apiService := app.NewAPI(logger, feedService, eventsService, membersService, clubService, guardService)
documentsService := app.NewDocumentsService(appStorage)
apiService := app.NewAPI(logger, feedService, eventsService, membersService, clubService, guardService, documentsService)

var mainGroupHandler *handler.GroupHandler
// Main API router.
Expand All @@ -112,7 +112,7 @@ func main() {
internalhttp.NewEventsHandler(jsonRenderer, *eventsService, logger, guardService),
internalhttp.NewMembersHandler(jsonRenderer, *membersService, logger, guardService),
internalhttp.NewMediaHandler(jsonRenderer, mediaService, logger, guardService),
// internalhttp.NewDocumentsHandler(jsonRenderer, *documentsService, logger, guardService),
internalhttp.NewDocumentsHandler(jsonRenderer, *documentsService, logger, guardService),
internalhttp.NewSwagHandler(jsonRenderer),
)
} else {
Expand All @@ -124,7 +124,7 @@ func main() {
internalhttp.NewEventsHandler(jsonRenderer, *eventsService, logger, guardService),
internalhttp.NewMembersHandler(jsonRenderer, *membersService, logger, guardService),
internalhttp.NewMediaHandler(jsonRenderer, mediaService, logger, guardService),
// internalhttp.NewDocumentsHandler(jsonRenderer, *documentsService, logger, guardService),
internalhttp.NewDocumentsHandler(jsonRenderer, *documentsService, logger, guardService),
internalhttp.NewSwagHandler(jsonRenderer),
)
}
Expand Down
29 changes: 16 additions & 13 deletions internal/app/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@ type API interface {
}

type apiService struct {
logger *logrus.Logger
feedService *FeedService
guardService *GuardService
eventsService *EventsService
clubsService *ClubService
membersService *MembersService
logger *logrus.Logger
feedService *FeedService
guardService *GuardService
eventsService *EventsService
clubsService *ClubService
membersService *MembersService
documentsService *DocumentsService
}

func NewAPI(logger *logrus.Logger, feed *FeedService, events *EventsService, membs *MembersService, club *ClubService, guard *GuardService) API {
func NewAPI(logger *logrus.Logger, feed *FeedService, events *EventsService,
membs *MembersService, club *ClubService, guard *GuardService, docs *DocumentsService) API {
return &apiService{
logger: logger,
feedService: feed,
guardService: guard,
eventsService: events,
clubsService: club,
membersService: membs,
logger: logger,
feedService: feed,
guardService: guard,
eventsService: events,
clubsService: club,
membersService: membs,
documentsService: docs,
}
}

Expand Down
124 changes: 32 additions & 92 deletions internal/app/documents.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,145 +14,85 @@ import (
type documentsServiceStorage interface {
GetAllDocuments(ctx context.Context) ([]domain.Document, error)
GetDocument(ctx context.Context, id int) (domain.Document, error)
GetDocumentsByCategory(ctx context.Context, categoryID int) ([]domain.Document, error)
GetDocumentsByClubID(ctx context.Context, clubID int) ([]domain.Document, error)
PostDocument(ctx context.Context, name, key string, clubId int) error
DeleteDocument(ctx context.Context, id int) (string, error)
UpdateDocument(ctx context.Context, id int, name, key string, clubId int) (string, error)
GetAllDocumentKeys(ctx context.Context) ([]string, error)
UploadObject(ctx context.Context, name string, bucketName string, data []byte) (string, error)
DeleteObject(ctx context.Context, name string, bucketName string) error
GetAllObjectNames(ctx context.Context, bucketName string) ([]string, error)
PostDocument(ctx context.Context, name, key string, data []byte, clubId, categoryId int) error
DeleteDocument(ctx context.Context, id int) error
UpdateDocument(ctx context.Context, id int, name, key string, data []byte, clubId, categoryId int) error
CleanupDocuments(ctx context.Context, logger *logrus.Logger) error
}

type DocumentsService struct {
bucketName string
storage documentsServiceStorage
storage documentsServiceStorage
}

func NewDocumentsService(storage documentsServiceStorage, bucketName string) *DocumentsService {
return &DocumentsService{bucketName: bucketName, storage: storage}
func NewDocumentsService(storage documentsServiceStorage) *DocumentsService {
return &DocumentsService{storage: storage}
}

func (s *DocumentsService) GetAllDocuments(ctx context.Context) (*responses.GetAllDocuments, error) {
docs, err := s.storage.GetAllDocuments(ctx)
if err != nil {
return nil, fmt.Errorf("can't storage.GetAllDocuments: %w", err)
}
return mapper.MakeResponseAllDocuments(docs, s.bucketName)
return mapper.MakeResponseAllDocuments(docs)
}

func (s *DocumentsService) GetDocument(ctx context.Context, id int) (*responses.GetDocument, error) {
doc, err := s.storage.GetDocument(ctx, id)
if err != nil {
return nil, fmt.Errorf("can't storage.GetDocument: %w", err)
}
return mapper.MakeResponseDocument(&doc, s.bucketName)
return mapper.MakeResponseDocument(&doc)
}

func (s *DocumentsService) GetDocumentsByCategory(ctx context.Context, categoryID int) (*responses.GetDocumentsByCategory, error) {
docs, err := s.storage.GetDocumentsByCategory(ctx, categoryID)
if err != nil {
return nil, fmt.Errorf("can't storage.GetDocumentsByCategory: %w", err)
}
return mapper.MakeResponseDocumentsByCategory(docs)
}

func (s *DocumentsService) GetDocumentsByClubID(ctx context.Context, clubID int) (*responses.GetDocumentsByClubID, error) {
docs, err := s.storage.GetDocumentsByClubID(ctx, clubID)
if err != nil {
return nil, fmt.Errorf("can't storage.GetDocumentsByClubID: %w", err)
}
return mapper.MakeResponseDocumentsByClubID(docs, s.bucketName)
return mapper.MakeResponseDocumentsByClubID(docs)
}

func (s *DocumentsService) PostDocument(ctx context.Context, doc *requests.PostDocument) error {
_, err := s.storage.UploadObject(ctx, doc.Name, s.bucketName, doc.Data)
if err != nil {
return fmt.Errorf("can't storage.UploadObject: %w", err)
}
func (s *DocumentsService) PostDocument(ctx context.Context, doc *requests.PostDocument) (*responses.PostDocument, error) {
var key = fmt.Sprintf("%d/%s", doc.ClubID, doc.Name)

err = s.storage.PostDocument(ctx, doc.Name, doc.Name, doc.ClubID)
err := s.storage.PostDocument(ctx, doc.Name, key, doc.Data, doc.ClubID, doc.CategoryID)
if err != nil {
s.storage.DeleteObject(ctx, doc.Name, s.bucketName)
return fmt.Errorf("can't storage.PostDocument: %w", err)
return nil, fmt.Errorf("can't storage.PostDocument: %w", err)
}

return nil
return mapper.MakeResponsePostDocument(key)
}

func (s *DocumentsService) DeleteDocument(ctx context.Context, id int) error {
name, err := s.storage.DeleteDocument(ctx, id)
err := s.storage.DeleteDocument(ctx, id)
if err != nil {
return fmt.Errorf("can't storage.DeleteDocument: %w", err)
}

err = s.storage.DeleteObject(ctx, name, s.bucketName)
if err != nil {
return fmt.Errorf("can't storage.DeleteObject: %w", err)
}

return nil
}

func (s *DocumentsService) UpdateDocument(ctx context.Context, doc *requests.UpdateDocument) error {
_, err := s.storage.UploadObject(ctx, doc.Name, s.bucketName, doc.Data)
if err != nil {
return fmt.Errorf("can't storage.UploadObject: %w", err)
}
func (s *DocumentsService) UpdateDocument(ctx context.Context, doc *requests.UpdateDocument) (*responses.UpdateDocument, error) {
var key = fmt.Sprintf("%d/%s", doc.ClubID, doc.Name)

prevName, err := s.storage.UpdateDocument(ctx, doc.ID, doc.Name, doc.Name, doc.ClubID)
err := s.storage.UpdateDocument(ctx, doc.ID, doc.Name, key, doc.Data, doc.ClubID, doc.CategoryID)
if err != nil {
s.storage.DeleteObject(ctx, doc.Name, s.bucketName)
return fmt.Errorf("can't storage.UpdateDocument: %w", err)
return nil, fmt.Errorf("can't storage.UpdateDocument: %w", err)
}

if prevName != doc.Name {
err = s.storage.DeleteObject(ctx, prevName, s.bucketName)
if err != nil {
return fmt.Errorf("can't storage.DeleteObject: %w", err)
}
}

return nil
return mapper.MakeResponseUpdateDocument(key)
}

func (s *DocumentsService) ClearUnknownDocuments(ctx context.Context, logger *logrus.Logger) error {
logger.Infof("Started deleting unknown documents from object storage...")

keys, err := s.storage.GetAllDocumentKeys(ctx)
if err != nil {
logger.Warnf("Failed to get all document keys: %v", err)
}
logger.Infof("Found %d documents in database: %v", len(keys), keys)

logger.Infof("Trying to get all document names from object storage...")
objNames, err := s.storage.GetAllObjectNames(ctx, s.bucketName)
if err != nil {
logger.Warnf("Failed to get all object names: %v", err)
return err
}

logger.Infof("Found %d documents in object storage: %v", len(objNames), objNames)

unknownKeys := make([]string, 0, len(objNames))

keysMap := make(map[string]struct{}, len(keys))
for _, key := range keys {
keysMap[key] = struct{}{}
}
for _, key := range objNames {
if _, ok := keysMap[key]; !ok {
unknownKeys = append(unknownKeys, key)
}
}

if len(unknownKeys) == 0 {
logger.Infof("No unknown documents found")
return nil
} else {
logger.Infof("Found %d unknown documents: %v", len(unknownKeys), unknownKeys)
}
logger.Infof("Started deleting unknown documents from object storage...")
for _, key := range unknownKeys {
err := s.storage.DeleteObject(ctx, key, s.bucketName)
if err != nil {
logger.Warnf("Delete unknown document failed from object storage: %v", err)
return err
}
}
logger.Infof("Delete unknown documents from object storage successful!")

return nil
func (s *DocumentsService) CleanupDocuments(ctx context.Context, logger *logrus.Logger) error {
return s.storage.CleanupDocuments(ctx, logger)
}
61 changes: 46 additions & 15 deletions internal/app/mapper/documents.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,72 @@ import (
"github.com/STUD-IT-team/bmstu-stud-web-backend/internal/domain/responses"
)

func MakeResponseAllDocuments(d []domain.Document, bucketName string) (*responses.GetAllDocuments, error) {
func MakeResponseAllDocuments(d []domain.Document) (*responses.GetAllDocuments, error) {
documents := make([]responses.Document, 0, len(d))
for _, v := range d {
documents = append(documents,
responses.Document{
ID: v.ID,
Name: v.Name,
Key: bucketName + "/" + v.Key,
ClubID: v.ClubID,
ID: v.ID,
Name: v.Name,
Key: v.Key,
ClubID: v.ClubID,
CategoryID: v.CategoryID,
})
}

return &responses.GetAllDocuments{Documents: documents}, nil
}

func MakeResponseDocument(v *domain.Document, bucketName string) (*responses.GetDocument, error) {
func MakeResponseDocument(v *domain.Document) (*responses.GetDocument, error) {
return &responses.GetDocument{
ID: v.ID,
Name: v.Name,
Key: bucketName + "/" + v.Key,
ClubID: v.ClubID,
ID: v.ID,
Name: v.Name,
Key: v.Key,
ClubID: v.ClubID,
CategoryID: v.CategoryID,
}, nil
}

func MakeResponseDocumentsByClubID(d []domain.Document, bucketName string) (*responses.GetDocumentsByClubID, error) {
func MakeResponseDocumentsByClubID(d []domain.Document) (*responses.GetDocumentsByClubID, error) {
documents := make([]responses.Document, 0, len(d))
for _, v := range d {
documents = append(documents,
responses.Document{
ID: v.ID,
Name: v.Name,
Key: bucketName + "/" + v.Key,
ClubID: v.ClubID,
ID: v.ID,
Name: v.Name,
Key: v.Key,
ClubID: v.ClubID,
CategoryID: v.CategoryID,
})
}

return &responses.GetDocumentsByClubID{Documents: documents}, nil
}

func MakeResponseDocumentsByCategory(d []domain.Document) (*responses.GetDocumentsByCategory, error) {
documents := make([]responses.Document, 0, len(d))
for _, v := range d {
documents = append(documents,
responses.Document{
ID: v.ID,
Name: v.Name,
Key: v.Key,
ClubID: v.ClubID,
CategoryID: v.CategoryID,
})
}

return &responses.GetDocumentsByCategory{Documents: documents}, nil
}

func MakeResponsePostDocument(key string) (*responses.PostDocument, error) {
return &responses.PostDocument{
NewKey: key,
}, nil
}

func MakeResponseUpdateDocument(key string) (*responses.UpdateDocument, error) {
return &responses.UpdateDocument{
NewKey: key,
}, nil
}
9 changes: 5 additions & 4 deletions internal/domain/document.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package domain

type Document struct {
ID int `json:"id"`
Name string `json:"name"`
Key string `json:"key"`
ClubID int `json:"club_id"`
ID int `json:"id"`
Name string `json:"name"`
Key string `json:"key"`
ClubID int `json:"club_id"`
CategoryID int `json:"category_id"`
}
28 changes: 28 additions & 0 deletions internal/domain/requests/get-documents-by-category.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package requests

import (
"fmt"
"net/http"
"strconv"

"github.com/go-chi/chi"
)

type GetDocumentsByCategory struct {
ID int `json:"id"`
}

func (f *GetDocumentsByCategory) Bind(req *http.Request) error {
id, err := strconv.Atoi(chi.URLParam(req, "category_id"))
if err != nil {
return fmt.Errorf("can't Atoi id on GetDocumentsByCategory.Bind: %w", err)
}

f.ID = id

return f.validate()
}

func (f *GetDocumentsByCategory) validate() error {
return nil
}
Loading

0 comments on commit 6532077

Please sign in to comment.