Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions cypress/e2e/training-datasets.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,37 @@ describe('Training Dataset Management', () => {
expect($input[0].validationMessage).to.contain('Please fill out this field.');
});
});

it('validation error for duplicated name', () => {
cy.get('#training-datasets-listing div div a div').first().invoke('text').then(name => {
let alreadyExisting = name
cy.wrap(alreadyExisting).as('alreadyExisting')
})
cy.get('main a')
.contains('Create Training Dataset')
.click();

cy.get('@alreadyExisting').then(alreadyExisting => {
cy.get('#train-dataset-name').type(alreadyExisting);
})

cy.get('#find-aods-form input').type('/alice/sim/2024/LHC24f3/0/523397');
cy.get('#find-aods-form button').click();

cy.get('#file-list ul').children().its('length').should('be.gt', 0);

selectFiles([
'#file-list li:first-child',
'#file-list li:first-child',
'#file-list li:first-child',
'#file-list li:first-child',
'#file-list li:last-child'
]);

cy.get('#submit-dataset-form button[type="submit"]')
.contains('Submit')
.click();

cy.get('#errors').invoke('text').should('eq', 'Name must be unique\n')
});
});
18 changes: 18 additions & 0 deletions cypress/e2e/training-machines.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,22 @@ describe('Training Machine Management', () => {
expect($input[0].validationMessage).to.contain('Please fill out this field.');
});
});

it('validation error for duplicated name', () => {
cy.get('tbody tr').first().children().first().invoke('text').then(name => {
let alreadyExisting = name
cy.wrap(alreadyExisting).as('alreadyExisting')
})

cy.get('main a')
.contains('Register Training Machine')
.click();

cy.get('@alreadyExisting').then(alreadyExisting => {
cy.get('input[name="name"]').type(alreadyExisting);
})
cy.get('button').click();

cy.get('#errors').invoke('text').should('eq', 'Name must be unique\n')
});
});
21 changes: 20 additions & 1 deletion cypress/e2e/training-tasks.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('Training Tasks Management', () => {
cy.get('select[name="trainingDatasetId"]').select('LHC24b1b');
cy.get('button').click();

let tmObject = cy.contains('tr', testName)
let tmObject = cy.contains('tr', testName)
tmObject.should('exist')
});

Expand All @@ -46,4 +46,23 @@ describe('Training Tasks Management', () => {
expect($input[0].validationMessage).to.contain('Please fill out this field.');
});
});

it('validation error for duplicated name', () => {
cy.get('tbody tr').first().children().first().invoke('text').then(name => {
let alreadyExisting = name
cy.wrap(alreadyExisting).as('alreadyExisting')
})

cy.get('main a')
.contains('Create Training Task')
.click();

cy.get('@alreadyExisting').then(alreadyExisting => {
cy.get('input[name="name"]').type(alreadyExisting);
})
cy.get('select[name="trainingDatasetId"]').select('LHC24b1b');
cy.get('button').click();

cy.get('#errors').invoke('text').should('eq', 'Name must be unique\n')
});
});
4 changes: 4 additions & 0 deletions internal/handler/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import (
"github.com/mytkom/AliceTraINT/internal/service"
)

const (
errMsgUserUnauthorized string = "user unauthorized"
)

func handleServiceError(w http.ResponseWriter, err error) {
switch err.(type) {
case *service.ErrHandlerNotFound:
Expand Down
15 changes: 10 additions & 5 deletions internal/handler/queue_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handler

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
Expand All @@ -17,6 +18,10 @@ type QueueHandler struct {
QueueService service.IQueueService
}

const (
errMsgUnauthorizedMachine string = "unauthorized machine"
)

func (qh *QueueHandler) parseId(r *http.Request) (uint, error) {
idStr := r.PathValue("id")
id, err := strconv.ParseUint(idStr, 10, 32)
Expand All @@ -39,12 +44,12 @@ func (qh *QueueHandler) trainingMachineFromPath(r *http.Request) (*models.Traini
}

if tt.TrainingMachineId == nil {
return nil, nil, fmt.Errorf("unauthorized machine")
return nil, nil, errors.New(errMsgUnauthorizedMachine)
}

tm, err := qh.QueueService.AuthorizeTrainingMachine(r.Header.Get("Secret-Id"), *tt.TrainingMachineId)
if err != nil {
return nil, nil, fmt.Errorf("unauthorized machine")
return nil, nil, errors.New(errMsgUnauthorizedMachine)
}

return tm, tt, nil
Expand All @@ -57,7 +62,7 @@ func (qh *QueueHandler) UpdateStatus(w http.ResponseWriter, r *http.Request) {

_, tt, err := qh.trainingMachineFromPath(r)
if err != nil {
http.Error(w, "unauthorized machine", http.StatusUnauthorized)
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}

Expand All @@ -84,7 +89,7 @@ func (qh *QueueHandler) QueryTask(w http.ResponseWriter, r *http.Request) {

tm, err := qh.QueueService.AuthorizeTrainingMachine(r.Header.Get("Secret-Id"), uint(tmId))
if err != nil {
http.Error(w, "unauthorized machine", http.StatusUnauthorized)
http.Error(w, errMsgUnauthorizedMachine, http.StatusUnauthorized)
return
}

Expand Down Expand Up @@ -115,7 +120,7 @@ func (qh *QueueHandler) QueryTask(w http.ResponseWriter, r *http.Request) {
func (qh *QueueHandler) CreateTrainingTaskResult(w http.ResponseWriter, r *http.Request) {
_, tt, err := qh.trainingMachineFromPath(r)
if err != nil {
http.Error(w, "unauthorized machine", http.StatusUnauthorized)
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}

Expand Down
6 changes: 3 additions & 3 deletions internal/handler/training_dataset_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (h *TrainingDatasetHandler) List(w http.ResponseWriter, r *http.Request) {

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

Expand Down Expand Up @@ -119,7 +119,7 @@ func (h *TrainingDatasetHandler) Create(w http.ResponseWriter, r *http.Request)

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}
trainingDataset.UserId = user.ID
Expand All @@ -144,7 +144,7 @@ func (h *TrainingDatasetHandler) Delete(w http.ResponseWriter, r *http.Request)

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

Expand Down
14 changes: 7 additions & 7 deletions internal/handler/training_machine_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ func (h *TrainingMachineHandler) List(w http.ResponseWriter, r *http.Request) {

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

trainingMachines, err := h.Service.GetAll(user.ID, utils.IsUserScoped(r))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
handleServiceError(w, err)
return
}

Expand All @@ -80,7 +80,7 @@ func (h *TrainingMachineHandler) Show(w http.ResponseWriter, r *http.Request) {

trainingMachine, err := h.Service.GetByID(uint(id))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
handleServiceError(w, err)
return
}

Expand Down Expand Up @@ -123,14 +123,14 @@ func (h *TrainingMachineHandler) Create(w http.ResponseWriter, r *http.Request)

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}
trainingMachine.UserId = user.ID

secretKey, err := h.Service.Create(&trainingMachine)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
handleServiceError(w, err)
return
}

Expand All @@ -154,13 +154,13 @@ func (h *TrainingMachineHandler) Delete(w http.ResponseWriter, r *http.Request)

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

err = h.Service.Delete(user.ID, uint(trainingMachineId))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
handleServiceError(w, err)
return
}

Expand Down
10 changes: 6 additions & 4 deletions internal/handler/training_task_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,22 @@ func (h *TrainingTaskHandler) List(w http.ResponseWriter, r *http.Request) {

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

trainingTasks, err := h.Service.GetAll(user.ID, utils.IsUserScoped(r))
if err != nil {
handleServiceError(w, err)
return
}

err = h.ExecuteTemplate(w, "training-tasks_list", TemplateData{
TrainingTasks: trainingTasks,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

Expand Down Expand Up @@ -124,7 +126,7 @@ func (h *TrainingTaskHandler) New(w http.ResponseWriter, r *http.Request) {

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}

Expand Down Expand Up @@ -155,14 +157,14 @@ func (h *TrainingTaskHandler) Create(w http.ResponseWriter, r *http.Request) {

user, ok := middleware.GetLoggedUser(r)
if !ok || user == nil {
http.Error(w, "user not found in context", http.StatusUnauthorized)
http.Error(w, errMsgUserUnauthorized, http.StatusUnauthorized)
return
}
trainingTask.UserId = user.ID

err = h.Service.Create(&trainingTask)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
handleServiceError(w, err)
return
}

Expand Down
40 changes: 35 additions & 5 deletions internal/service/training_machine_service.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package service

import (
"errors"

"github.com/mytkom/AliceTraINT/internal/db/models"
"github.com/mytkom/AliceTraINT/internal/db/repository"
"gorm.io/gorm"
)

type ITrainingMachineService interface {
Expand All @@ -24,6 +27,8 @@ func NewTrainingMachineService(repo *repository.RepositoryContext, hasher Hasher
}
}

var errMachineNotFound = NewErrHandlerNotFound("TrainingMachine")

func (s *TrainingMachineService) Create(tm *models.TrainingMachine) (string, error) {
secretKey, err := s.Hasher.GenerateKey()
if err != nil {
Expand All @@ -37,7 +42,14 @@ func (s *TrainingMachineService) Create(tm *models.TrainingMachine) (string, err

err = s.TrainingMachine.Create(tm)
if err != nil {
return "", err
if errors.Is(err, gorm.ErrDuplicatedKey) {
return "", &ErrHandlerValidation{
Field: "Name",
Msg: errMsgNotUnique,
}
} else {
return "", errInternalServerError
}
}

return secretKey, nil
Expand All @@ -50,22 +62,40 @@ func (s *TrainingMachineService) GetAll(loggedUserId uint, userScoped bool) ([]m
if userScoped {
trainingMachines, err = s.TrainingMachine.GetAllUser(loggedUserId)
if err != nil {
return nil, err
return nil, errInternalServerError
}
} else {
trainingMachines, err = s.TrainingMachine.GetAll()
if err != nil {
return nil, err
return nil, errInternalServerError
}
}

return trainingMachines, nil
}

func (s *TrainingMachineService) GetByID(id uint) (*models.TrainingMachine, error) {
return s.TrainingMachine.GetByID(uint(id))
tm, err := s.TrainingMachine.GetByID(uint(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errMachineNotFound
} else {
return nil, errInternalServerError
}
}

return tm, nil
}

func (s *TrainingMachineService) Delete(loggedUserId uint, id uint) error {
return s.TrainingMachine.Delete(loggedUserId, id)
err := s.TrainingMachine.Delete(loggedUserId, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errMachineNotFound
} else {
return errInternalServerError
}
}

return nil
}
Loading
Loading