From dc07668f8b48826a6f947e946a4763cda420dbc0 Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Tue, 19 May 2020 19:56:04 +0530 Subject: [PATCH 1/8] Added create endpoint for reported recognition api --- go-backend/db/db.go | 3 + go-backend/db/reported_recognition.go | 82 +++++++++++++++++++ ...3448_create_reported_recognitions.down.sql | 1 + ...893448_create_reported_recognitions.up.sql | 10 +++ .../service/reported_recognition_http.go | 63 ++++++++++++++ go-backend/service/router.go | 3 + 6 files changed, 162 insertions(+) create mode 100644 go-backend/db/reported_recognition.go create mode 100644 go-backend/migrations/1589893448_create_reported_recognitions.down.sql create mode 100644 go-backend/migrations/1589893448_create_reported_recognitions.up.sql create mode 100644 go-backend/service/reported_recognition_http.go diff --git a/go-backend/db/db.go b/go-backend/db/db.go index d730cddf2..750d1c9e9 100644 --- a/go-backend/db/db.go +++ b/go-backend/db/db.go @@ -21,4 +21,7 @@ type Storer interface { CreateCoreValue(context.Context, int64, CoreValue) (CoreValue, error) DeleteCoreValue(context.Context, int64, int64) error UpdateCoreValue(context.Context, int64, int64, CoreValue) (CoreValue, error) + + //Reported Recognition + CreateReportedRecognition(context.Context, int64, ReportedRecognition) (ReportedRecognition, error) } diff --git a/go-backend/db/reported_recognition.go b/go-backend/db/reported_recognition.go new file mode 100644 index 000000000..0bc7c970a --- /dev/null +++ b/go-backend/db/reported_recognition.go @@ -0,0 +1,82 @@ +package db + +import ( + "context" + "time" + + logger "github.com/sirupsen/logrus" +) + +var REPORTED_RECOGNITION_TYPE = []string{"fraud", "not_relevant", "incorrect"} + +const ( + createReportedRecognitionQuery = `INSERT INTO reported_recognitions (recognition_id, type_of_reporting, + reason_for_reporting, reported_by, reported_at) VALUES ($1, $2, $3, $4, $5) + RETURNING id, recognition_id, type_of_reporting, reason_for_reporting, reported_by, reported_at` +) + +type ReportedRecognition struct { + ID int64 `db:"id" json:"id"` + RecognitionID *int64 `db:"recognition_id" json:"recognition_id"` + TypeOfReporting string `db:"type_of_reporting" json:"mark_as"` + ReasonForReporting string `db:"reason_for_reporting" json:"reason"` + ReportedBy *int64 `db:"reported_by" json:"reported_by"` + ReportedAt int64 `db:"reported_at" json:"reported_at"` + CreatedAt time.Time `db:"created_at" json:"-"` + UpdatedAt time.Time `db:"updated_at" json:"-"` +} + +func include(slice []string, val string) bool { + for _, item := range slice { + if item == val { + return true + } + } + return false +} + +func (reportedRecognition ReportedRecognition) Validate() (valid bool, errFields map[string]string) { + errFields = make(map[string]string) + + if reportedRecognition.TypeOfReporting == "" { + errFields["mark_as"] = "Can't be blank" + } else { + ok := include(REPORTED_RECOGNITION_TYPE, reportedRecognition.TypeOfReporting) + if !ok { + errFields["mark_as"] = "Invalid reported recognition type" + } + } + + if reportedRecognition.ReasonForReporting == "" { + errFields["reason"] = "Can't be blank" + } + + if len(errFields) == 0 { + valid = true + } + return +} + +func (s *pgStore) CreateReportedRecognition(ctx context.Context, recognitionID int64, reportedRecognition ReportedRecognition) (resp ReportedRecognition, err error) { + now := time.Now() + err = s.db.GetContext( + ctx, + &resp, + createReportedRecognitionQuery, + recognitionID, + reportedRecognition.TypeOfReporting, + reportedRecognition.ReasonForReporting, + reportedRecognition.ReportedBy, + now.Unix(), + ) + if err != nil { + logger.WithFields(logger.Fields{ + "err": err.Error(), + "recognitionID": recognitionID, + "reported_recognition_params": reportedRecognition, + }).Error("Error while creating reported recognition") + return + } + + return +} diff --git a/go-backend/migrations/1589893448_create_reported_recognitions.down.sql b/go-backend/migrations/1589893448_create_reported_recognitions.down.sql new file mode 100644 index 000000000..7032bcc1b --- /dev/null +++ b/go-backend/migrations/1589893448_create_reported_recognitions.down.sql @@ -0,0 +1 @@ +DROP TABLE reported_recognitions; diff --git a/go-backend/migrations/1589893448_create_reported_recognitions.up.sql b/go-backend/migrations/1589893448_create_reported_recognitions.up.sql new file mode 100644 index 000000000..91144ab5f --- /dev/null +++ b/go-backend/migrations/1589893448_create_reported_recognitions.up.sql @@ -0,0 +1,10 @@ +CREATE TABLE reported_recognitions ( + id SERIAL PRIMARY KEY NOT NULL UNIQUE, + recognition_id integer REFERENCES recognitions(id), + type_of_reporting varchar(50), + reason_for_reporting TEXT, + reported_by INTEGER REFERENCES users(id), + reported_at BIGINT, + created_at timestamp with time zone NOT NULL default current_timestamp, + updated_at timestamp with time zone NOT NULL +); \ No newline at end of file diff --git a/go-backend/service/reported_recognition_http.go b/go-backend/service/reported_recognition_http.go new file mode 100644 index 000000000..633230e9a --- /dev/null +++ b/go-backend/service/reported_recognition_http.go @@ -0,0 +1,63 @@ +package service + +import ( + "encoding/json" + "net/http" + "strconv" + + "github.com/gorilla/mux" + logger "github.com/sirupsen/logrus" + "joshsoftware/peerly/db" +) + +func createReportedRecognitionHandler(deps Dependencies) http.HandlerFunc { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + userID := int64(1) //Extract for token + + vars := mux.Vars(req) + recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while parsing recognition_id from url") + rw.WriteHeader(http.StatusBadRequest) + return + } + + var reportedRecognition db.ReportedRecognition + err = json.NewDecoder(req.Body).Decode(&reportedRecognition) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while decoding request data") + repsonse(rw, http.StatusBadRequest, errorResponse{ + Error: messageObject{ + Message: "Invalid json request body", + }, + }) + return + } + reportedRecognition.ReportedBy = &userID + + ok, errFields := reportedRecognition.Validate() + if !ok { + repsonse(rw, http.StatusBadRequest, errorResponse{ + Error: errorObject{ + Code: "invalid-reported-recognition", + Fields: errFields, + messageObject: messageObject{"Invalid reported recognition data"}, + }, + }) + return + } + + resp, err := deps.Store.CreateReportedRecognition(req.Context(), recognitionID, reportedRecognition) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while creating reported recognition") + repsonse(rw, http.StatusInternalServerError, errorResponse{ + Error: messageObject{ + Message: "Internal server error", + }, + }) + return + } + + repsonse(rw, http.StatusCreated, successResponse{Data: resp}) + }) +} diff --git a/go-backend/service/router.go b/go-backend/service/router.go index a6654d1f9..884768ab7 100644 --- a/go-backend/service/router.go +++ b/go-backend/service/router.go @@ -29,6 +29,9 @@ func InitRouter(deps Dependencies) (router *mux.Router) { router.HandleFunc("/organisations/{organisation_id:[0-9]+}/core_values/{id:[0-9]+}", deleteCoreValueHandler(deps)).Methods(http.MethodDelete).Headers(versionHeader, v1) router.HandleFunc("/organisations/{organisation_id:[0-9]+}/core_values/{id:[0-9]+}", updateCoreValueHandler(deps)).Methods(http.MethodPut).Headers(versionHeader, v1) + //reported recognition + router.HandleFunc("/recognitions/{recognition_id:[0-9]+}/report", createReportedRecognitionHandler(deps)).Methods(http.MethodPost).Headers(versionHeader, v1) + //users router.HandleFunc("/users", listUsersHandler(deps)).Methods(http.MethodGet).Headers(versionHeader, v1) From 79994687e19606a7431d8b4bbe8baf708488fb02 Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Wed, 20 May 2020 12:57:55 +0530 Subject: [PATCH 2/8] Added handler test cases for reported recognition api --- go-backend/db/mock.go | 5 + go-backend/db/reported_recognition.go | 4 +- .../service/reported_recognition_http_test.go | 152 ++++++++++++++++++ go-backend/service/user_http_test.go | 1 + 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 go-backend/service/reported_recognition_http_test.go diff --git a/go-backend/db/mock.go b/go-backend/db/mock.go index 2ced6572a..c200c2f76 100644 --- a/go-backend/db/mock.go +++ b/go-backend/db/mock.go @@ -64,3 +64,8 @@ func (m *DBMockStore) UpdateOrganization(ctx context.Context, org Organization, args := m.Called(ctx, org, id) return args.Get(0).(Organization), args.Error(1) } + +func (m *DBMockStore) CreateReportedRecognition(ctx context.Context, recognitionID int64, reportedRecognition ReportedRecognition) (resp ReportedRecognition, err error) { + args := m.Called(ctx, recognitionID, reportedRecognition) + return args.Get(0).(ReportedRecognition), args.Error(1) +} diff --git a/go-backend/db/reported_recognition.go b/go-backend/db/reported_recognition.go index 0bc7c970a..c9fa245ac 100644 --- a/go-backend/db/reported_recognition.go +++ b/go-backend/db/reported_recognition.go @@ -2,6 +2,7 @@ package db import ( "context" + "strings" "time" logger "github.com/sirupsen/logrus" @@ -35,12 +36,13 @@ func include(slice []string, val string) bool { return false } -func (reportedRecognition ReportedRecognition) Validate() (valid bool, errFields map[string]string) { +func (reportedRecognition *ReportedRecognition) Validate() (valid bool, errFields map[string]string) { errFields = make(map[string]string) if reportedRecognition.TypeOfReporting == "" { errFields["mark_as"] = "Can't be blank" } else { + reportedRecognition.TypeOfReporting = strings.ToLower(reportedRecognition.TypeOfReporting) ok := include(REPORTED_RECOGNITION_TYPE, reportedRecognition.TypeOfReporting) if !ok { errFields["mark_as"] = "Invalid reported recognition type" diff --git a/go-backend/service/reported_recognition_http_test.go b/go-backend/service/reported_recognition_http_test.go new file mode 100644 index 000000000..5697d1b73 --- /dev/null +++ b/go-backend/service/reported_recognition_http_test.go @@ -0,0 +1,152 @@ +package service + +import ( + "errors" + "fmt" + "net/http" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "joshsoftware/peerly/db" +) + +type ReportedRecognitionHandlerTestSuite struct { + suite.Suite + + dbMock *db.DBMockStore +} + +func (suite *ReportedRecognitionHandlerTestSuite) SetupTest() { + suite.dbMock = &db.DBMockStore{} +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionSuccess() { + now := time.Now().Unix() + userID := int64(1) + recognitionID := int64(1) + suite.dbMock.On("CreateReportedRecognition", mock.Anything, mock.Anything, mock.Anything).Return(db.ReportedRecognition{ + ID: 1, + RecognitionID: &recognitionID, + TypeOfReporting: "fraud", + ReasonForReporting: "Reason Test", + ReportedBy: &userID, + ReportedAt: now, + }, nil) + + body := `{ + "mark_as": "fraud", + "reason": "Reason Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + expectedBody := fmt.Sprintf(`{"data":{"id":1,"recognition_id":1,"mark_as":"fraud","reason":"Reason Test","reported_by":1,"reported_at":%v}}`, now) + + assert.Equal(suite.T(), http.StatusCreated, recorder.Code) + assert.Equal(suite.T(), expectedBody, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionWhenInvalidJSONFormat() { + body := `{ + "mark_as": "fraud" + "reason": "Reason Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"message":"Invalid json request body"}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionWhenEmptyReportedRecognitionType() { + body := `{ + "mark_as": "", + "reason": "Reason Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"code":"invalid-reported-recognition","message":"Invalid reported recognition data","fields":{"mark_as":"Can't be blank"}}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionWhenInvalidReportedRecognitionType() { + body := `{ + "mark_as": "XYZ", + "reason": "Reason Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"code":"invalid-reported-recognition","message":"Invalid reported recognition data","fields":{"mark_as":"Invalid reported recognition type"}}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionWhenEmptyReasonForReport() { + body := `{ + "mark_as": "fraud", + "reason": "" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"code":"invalid-reported-recognition","message":"Invalid reported recognition data","fields":{"reason":"Can't be blank"}}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionWhenDBFailure() { + suite.dbMock.On("CreateReportedRecognition", mock.Anything, mock.Anything, mock.Anything).Return(db.ReportedRecognition{}, errors.New("error creating reported recognition")) + + body := `{ + "mark_as": "fraud", + "reason": "Reason Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/report", + "/recognitions/1/report", + body, + createReportedRecognitionHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusInternalServerError, recorder.Code) + assert.Equal(suite.T(), `{"error":{"message":"Internal server error"}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} diff --git a/go-backend/service/user_http_test.go b/go-backend/service/user_http_test.go index b039c56f0..b89cfaa19 100644 --- a/go-backend/service/user_http_test.go +++ b/go-backend/service/user_http_test.go @@ -30,6 +30,7 @@ func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(UsersHandlerTestSuite)) suite.Run(t, new(CoreValueHandlerTestSuite)) suite.Run(t, new(OrganizationHandlerTestSuite)) + suite.Run(t, new(ReportedRecognitionHandlerTestSuite)) } func (suite *UsersHandlerTestSuite) TestListUsersSuccess() { From 904f6825632eaa5666b9795ba0573bff185e8b9f Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Wed, 20 May 2020 13:50:00 +0530 Subject: [PATCH 3/8] Added created_at, updated_at in code for reported recognition --- go-backend/db/reported_recognition.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go-backend/db/reported_recognition.go b/go-backend/db/reported_recognition.go index c9fa245ac..b8d9780d5 100644 --- a/go-backend/db/reported_recognition.go +++ b/go-backend/db/reported_recognition.go @@ -12,8 +12,8 @@ var REPORTED_RECOGNITION_TYPE = []string{"fraud", "not_relevant", "incorrect"} const ( createReportedRecognitionQuery = `INSERT INTO reported_recognitions (recognition_id, type_of_reporting, - reason_for_reporting, reported_by, reported_at) VALUES ($1, $2, $3, $4, $5) - RETURNING id, recognition_id, type_of_reporting, reason_for_reporting, reported_by, reported_at` + reason_for_reporting, reported_by, reported_at, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id, recognition_id, type_of_reporting, reason_for_reporting, reported_by, reported_at, created_at, updated_at` ) type ReportedRecognition struct { @@ -70,6 +70,8 @@ func (s *pgStore) CreateReportedRecognition(ctx context.Context, recognitionID i reportedRecognition.ReasonForReporting, reportedRecognition.ReportedBy, now.Unix(), + now, + now, ) if err != nil { logger.WithFields(logger.Fields{ From 22cebb0dc8122bd514256480f5ea5c8714a667a8 Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Wed, 20 May 2020 15:37:03 +0530 Subject: [PATCH 4/8] remove unnessary pointer variable from reported recognition struct --- go-backend/db/reported_recognition.go | 4 ++-- go-backend/service/reported_recognition_http.go | 2 +- go-backend/service/reported_recognition_http_test.go | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/go-backend/db/reported_recognition.go b/go-backend/db/reported_recognition.go index b8d9780d5..e9bb9ad3e 100644 --- a/go-backend/db/reported_recognition.go +++ b/go-backend/db/reported_recognition.go @@ -18,10 +18,10 @@ const ( type ReportedRecognition struct { ID int64 `db:"id" json:"id"` - RecognitionID *int64 `db:"recognition_id" json:"recognition_id"` + RecognitionID int64 `db:"recognition_id" json:"recognition_id"` TypeOfReporting string `db:"type_of_reporting" json:"mark_as"` ReasonForReporting string `db:"reason_for_reporting" json:"reason"` - ReportedBy *int64 `db:"reported_by" json:"reported_by"` + ReportedBy int64 `db:"reported_by" json:"reported_by"` ReportedAt int64 `db:"reported_at" json:"reported_at"` CreatedAt time.Time `db:"created_at" json:"-"` UpdatedAt time.Time `db:"updated_at" json:"-"` diff --git a/go-backend/service/reported_recognition_http.go b/go-backend/service/reported_recognition_http.go index 633230e9a..cb4fbefb3 100644 --- a/go-backend/service/reported_recognition_http.go +++ b/go-backend/service/reported_recognition_http.go @@ -33,7 +33,7 @@ func createReportedRecognitionHandler(deps Dependencies) http.HandlerFunc { }) return } - reportedRecognition.ReportedBy = &userID + reportedRecognition.ReportedBy = userID ok, errFields := reportedRecognition.Validate() if !ok { diff --git a/go-backend/service/reported_recognition_http_test.go b/go-backend/service/reported_recognition_http_test.go index 5697d1b73..b6a693a96 100644 --- a/go-backend/service/reported_recognition_http_test.go +++ b/go-backend/service/reported_recognition_http_test.go @@ -24,14 +24,12 @@ func (suite *ReportedRecognitionHandlerTestSuite) SetupTest() { func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionSuccess() { now := time.Now().Unix() - userID := int64(1) - recognitionID := int64(1) suite.dbMock.On("CreateReportedRecognition", mock.Anything, mock.Anything, mock.Anything).Return(db.ReportedRecognition{ ID: 1, - RecognitionID: &recognitionID, + RecognitionID: int64(1), TypeOfReporting: "fraud", ReasonForReporting: "Reason Test", - ReportedBy: &userID, + ReportedBy: int64(1), ReportedAt: now, }, nil) From 93864cdec86dfc277ea363c3cff764ae322c5e7b Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Mon, 25 May 2020 16:50:05 +0530 Subject: [PATCH 5/8] Added recognition moderation api with handler test cases. --- go-backend/db/db.go | 3 + go-backend/db/mock.go | 5 + go-backend/db/recognition_moderation.go | 64 ++++++++++ ...840_create_recognition_moderation.down.sql | 1 + ...62840_create_recognition_moderation.up.sql | 10 ++ .../service/recognition_moderation_http.go | 63 ++++++++++ .../recognition_moderation_http_test.go | 112 ++++++++++++++++++ go-backend/service/router.go | 3 + go-backend/service/user_http_test.go | 1 + 9 files changed, 262 insertions(+) create mode 100644 go-backend/db/recognition_moderation.go create mode 100644 go-backend/migrations/1589962840_create_recognition_moderation.down.sql create mode 100644 go-backend/migrations/1589962840_create_recognition_moderation.up.sql create mode 100644 go-backend/service/recognition_moderation_http.go create mode 100644 go-backend/service/recognition_moderation_http_test.go diff --git a/go-backend/db/db.go b/go-backend/db/db.go index 750d1c9e9..0b85ba991 100644 --- a/go-backend/db/db.go +++ b/go-backend/db/db.go @@ -24,4 +24,7 @@ type Storer interface { //Reported Recognition CreateReportedRecognition(context.Context, int64, ReportedRecognition) (ReportedRecognition, error) + + //Recognition Moderation + CreateRecognitionModeration(context.Context, int64, RecognitionModeration) (RecognitionModeration, error) } diff --git a/go-backend/db/mock.go b/go-backend/db/mock.go index c200c2f76..02011e708 100644 --- a/go-backend/db/mock.go +++ b/go-backend/db/mock.go @@ -69,3 +69,8 @@ func (m *DBMockStore) CreateReportedRecognition(ctx context.Context, recognition args := m.Called(ctx, recognitionID, reportedRecognition) return args.Get(0).(ReportedRecognition), args.Error(1) } + +func (m *DBMockStore) CreateRecognitionModeration(ctx context.Context, recognitionID int64, recognitionModeration RecognitionModeration) (resp RecognitionModeration, err error) { + args := m.Called(ctx, recognitionID, recognitionModeration) + return args.Get(0).(RecognitionModeration), args.Error(1) +} diff --git a/go-backend/db/recognition_moderation.go b/go-backend/db/recognition_moderation.go new file mode 100644 index 000000000..0916f8091 --- /dev/null +++ b/go-backend/db/recognition_moderation.go @@ -0,0 +1,64 @@ +package db + +import ( + "context" + "time" + + logger "github.com/sirupsen/logrus" +) + +const ( + createRecognitionModerationQuery = `INSERT INTO recognition_moderation (recognition_id, is_inappropriate, + moderator_comment, moderated_by, moderated_at, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id, recognition_id, is_inappropriate, moderator_comment, moderated_by, moderated_at, created_at, updated_at` +) + +type RecognitionModeration struct { + ID int64 `db:"id" json:"id"` + RecognitionID int64 `db:"recognition_id" json:"recognition_id"` + IsInappropriate *bool `db:"is_inappropriate" json:"is_inappropriate"` + ModeratorComment string `db:"moderator_comment" json:"comment"` + ModeratedBy int64 `db:"moderated_by" json:"moderated_by"` + ModeratedAt int64 `db:"moderated_at" json:"moderated_at"` + CreatedAt time.Time `db:"created_at" json:"-"` + UpdatedAt time.Time `db:"updated_at" json:"-"` +} + +func (recognitionModeration *RecognitionModeration) Validate() (valid bool, errFields map[string]string) { + errFields = make(map[string]string) + + if recognitionModeration.IsInappropriate == nil { + errFields["is_inappropriate"] = "Can't be blank" + } + + if len(errFields) == 0 { + valid = true + } + return +} + +func (s *pgStore) CreateRecognitionModeration(ctx context.Context, recognitionID int64, recognitionModeration RecognitionModeration) (resp RecognitionModeration, err error) { + now := time.Now() + err = s.db.GetContext( + ctx, + &resp, + createRecognitionModerationQuery, + recognitionID, + recognitionModeration.IsInappropriate, + recognitionModeration.ModeratorComment, + recognitionModeration.ModeratedBy, + now.Unix(), + now, + now, + ) + if err != nil { + logger.WithFields(logger.Fields{ + "err": err.Error(), + "recognitionID": recognitionID, + "recognition_moderation_params": recognitionModeration, + }).Error("Error while creating recognition moderation") + return + } + + return +} diff --git a/go-backend/migrations/1589962840_create_recognition_moderation.down.sql b/go-backend/migrations/1589962840_create_recognition_moderation.down.sql new file mode 100644 index 000000000..9b3750eeb --- /dev/null +++ b/go-backend/migrations/1589962840_create_recognition_moderation.down.sql @@ -0,0 +1 @@ +DROP TABLE recognition_moderation; diff --git a/go-backend/migrations/1589962840_create_recognition_moderation.up.sql b/go-backend/migrations/1589962840_create_recognition_moderation.up.sql new file mode 100644 index 000000000..9ea29fe06 --- /dev/null +++ b/go-backend/migrations/1589962840_create_recognition_moderation.up.sql @@ -0,0 +1,10 @@ +CREATE TABLE recognition_moderation ( + id SERIAL PRIMARY KEY NOT NULL UNIQUE, + recognition_id integer REFERENCES recognitions(id), + is_inappropriate BOOLEAN default FALSE, + moderator_comment TEXT, + moderated_by INTEGER REFERENCES users(id), + moderated_at BIGINT, + created_at timestamp with time zone NOT NULL default current_timestamp, + updated_at timestamp with time zone NOT NULL +); diff --git a/go-backend/service/recognition_moderation_http.go b/go-backend/service/recognition_moderation_http.go new file mode 100644 index 000000000..2d9ce5166 --- /dev/null +++ b/go-backend/service/recognition_moderation_http.go @@ -0,0 +1,63 @@ +package service + +import ( + "encoding/json" + "net/http" + "strconv" + + "github.com/gorilla/mux" + logger "github.com/sirupsen/logrus" + "joshsoftware/peerly/db" +) + +func createRecognitionModerationHandler(deps Dependencies) http.HandlerFunc { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + userID := int64(1) //Extract for token + + vars := mux.Vars(req) + recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while parsing recognition_id from url") + rw.WriteHeader(http.StatusBadRequest) + return + } + + var recognitionModeration db.RecognitionModeration + err = json.NewDecoder(req.Body).Decode(&recognitionModeration) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while decoding request data") + repsonse(rw, http.StatusBadRequest, errorResponse{ + Error: messageObject{ + Message: "Invalid json request body", + }, + }) + return + } + recognitionModeration.ModeratedBy = userID + + ok, errFields := recognitionModeration.Validate() + if !ok { + repsonse(rw, http.StatusBadRequest, errorResponse{ + Error: errorObject{ + Code: "invalid-recognition-moderation", + Fields: errFields, + messageObject: messageObject{"Invalid recognition moderation data"}, + }, + }) + return + } + + resp, err := deps.Store.CreateRecognitionModeration(req.Context(), recognitionID, recognitionModeration) + if err != nil { + logger.WithField("err", err.Error()).Error("Error while creating recognition moderation") + repsonse(rw, http.StatusInternalServerError, errorResponse{ + Error: messageObject{ + Message: "Internal server error", + }, + }) + return + } + + repsonse(rw, http.StatusCreated, successResponse{Data: resp}) + }) +} diff --git a/go-backend/service/recognition_moderation_http_test.go b/go-backend/service/recognition_moderation_http_test.go new file mode 100644 index 000000000..fa8cbfd79 --- /dev/null +++ b/go-backend/service/recognition_moderation_http_test.go @@ -0,0 +1,112 @@ +package service + +import ( + "errors" + "fmt" + "net/http" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "joshsoftware/peerly/db" +) + +type RecognitionModerationHandlerTestSuite struct { + suite.Suite + + dbMock *db.DBMockStore +} + +func (suite *RecognitionModerationHandlerTestSuite) SetupTest() { + suite.dbMock = &db.DBMockStore{} +} + +func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerationSuccess() { + now := time.Now().Unix() + isInappropriate := false + suite.dbMock.On("CreateRecognitionModeration", mock.Anything, mock.Anything, mock.Anything).Return(db.RecognitionModeration{ + ID: 1, + RecognitionID: int64(1), + IsInappropriate: &isInappropriate, + ModeratorComment: "Comment Test", + ModeratedBy: int64(1), + ModeratedAt: now, + }, nil) + + body := `{ + "is_inappropriate": false, + "comment": "Comment Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/review", + "/recognitions/1/review", + body, + createRecognitionModerationHandler(Dependencies{Store: suite.dbMock}), + ) + expectedBody := fmt.Sprintf(`{"data":{"id":1,"recognition_id":1,"is_inappropriate":false,"comment":"Comment Test","moderated_by":1,"moderated_at":%v}}`, now) + + assert.Equal(suite.T(), http.StatusCreated, recorder.Code) + assert.Equal(suite.T(), expectedBody, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerationWhenInvalidJSONFormat() { + body := `{ + "is_inappropriate": false + "comment": "Comment Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/review", + "/recognitions/1/review", + body, + createRecognitionModerationHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"message":"Invalid json request body"}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerationWhenEmptyIsInappropriate() { + body := `{ + "comment": "Comment Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/review", + "/recognitions/1/review", + body, + createRecognitionModerationHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusBadRequest, recorder.Code) + assert.Equal(suite.T(), `{"error":{"code":"invalid-recognition-moderation","message":"Invalid recognition moderation data","fields":{"is_inappropriate":"Can't be blank"}}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} + +func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerationWhenDBFailure() { + suite.dbMock.On("CreateRecognitionModeration", mock.Anything, mock.Anything, mock.Anything).Return(db.RecognitionModeration{}, errors.New("error creating reported recognition")) + + body := `{ + "is_inappropriate": false, + "reason": "Comment Test" + }` + + recorder := makeHTTPCall( + http.MethodPost, + "/recognitions/{recognition_id:[0-9]+}/review", + "/recognitions/1/review", + body, + createRecognitionModerationHandler(Dependencies{Store: suite.dbMock}), + ) + + assert.Equal(suite.T(), http.StatusInternalServerError, recorder.Code) + assert.Equal(suite.T(), `{"error":{"message":"Internal server error"}}`, recorder.Body.String()) + suite.dbMock.AssertExpectations(suite.T()) +} diff --git a/go-backend/service/router.go b/go-backend/service/router.go index 884768ab7..6027ddc76 100644 --- a/go-backend/service/router.go +++ b/go-backend/service/router.go @@ -32,6 +32,9 @@ func InitRouter(deps Dependencies) (router *mux.Router) { //reported recognition router.HandleFunc("/recognitions/{recognition_id:[0-9]+}/report", createReportedRecognitionHandler(deps)).Methods(http.MethodPost).Headers(versionHeader, v1) + //recognition moderation + router.HandleFunc("/recognitions/{recognition_id:[0-9]+}/review", createRecognitionModerationHandler(deps)).Methods(http.MethodPost).Headers(versionHeader, v1) + //users router.HandleFunc("/users", listUsersHandler(deps)).Methods(http.MethodGet).Headers(versionHeader, v1) diff --git a/go-backend/service/user_http_test.go b/go-backend/service/user_http_test.go index b89cfaa19..cc36030a8 100644 --- a/go-backend/service/user_http_test.go +++ b/go-backend/service/user_http_test.go @@ -31,6 +31,7 @@ func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(CoreValueHandlerTestSuite)) suite.Run(t, new(OrganizationHandlerTestSuite)) suite.Run(t, new(ReportedRecognitionHandlerTestSuite)) + suite.Run(t, new(RecognitionModerationHandlerTestSuite)) } func (suite *UsersHandlerTestSuite) TestListUsersSuccess() { From 8699bffbf096da182a01538a260e171bf3109794 Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Tue, 16 Jun 2020 17:24:25 +0530 Subject: [PATCH 6/8] Added reported recognition and recognition moderation database test cases. --- go-backend/db/common_test.go | 8 ++ go-backend/db/mock.go | 2 +- go-backend/db/organization_test.go | 2 - go-backend/db/recognition_moderation_test.go | 86 +++++++++++++++++++ go-backend/db/reported_recognition_test.go | 84 ++++++++++++++++++ go-backend/service/common_http_test.go | 2 + .../service/recognition_moderation_http.go | 2 +- .../service/reported_recognition_http.go | 2 +- 8 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 go-backend/db/recognition_moderation_test.go create mode 100644 go-backend/db/reported_recognition_test.go diff --git a/go-backend/db/common_test.go b/go-backend/db/common_test.go index a8b613c37..e1c6438be 100644 --- a/go-backend/db/common_test.go +++ b/go-backend/db/common_test.go @@ -6,6 +6,12 @@ import ( logger "github.com/sirupsen/logrus" "github.com/stretchr/testify/suite" "testing" + "time" +) + +var ( + now time.Time + mockedRows *sqlmock.Rows ) func InitMockDB() (s Storer, sqlConn *sqlx.DB, sqlmockInstance sqlmock.Sqlmock) { @@ -27,4 +33,6 @@ func InitMockDB() (s Storer, sqlConn *sqlx.DB, sqlmockInstance sqlmock.Sqlmock) func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(OrganizationTestSuite)) suite.Run(t, new(RecognitionHi5TestSuite)) + suite.Run(t, new(ReportedRecognitionTestSuite)) + suite.Run(t, new(RecognitionModerationTestSuite)) } diff --git a/go-backend/db/mock.go b/go-backend/db/mock.go index c99c7ada6..813b9d63a 100644 --- a/go-backend/db/mock.go +++ b/go-backend/db/mock.go @@ -154,4 +154,4 @@ func (m *DBMockStore) CreateReportedRecognition(ctx context.Context, recognition func (m *DBMockStore) CreateRecognitionModeration(ctx context.Context, recognitionID int64, recognitionModeration RecognitionModeration) (resp RecognitionModeration, err error) { args := m.Called(ctx, recognitionID, recognitionModeration) return args.Get(0).(RecognitionModeration), args.Error(1) -} \ No newline at end of file +} diff --git a/go-backend/db/organization_test.go b/go-backend/db/organization_test.go index d73ebae72..b80ffc98a 100644 --- a/go-backend/db/organization_test.go +++ b/go-backend/db/organization_test.go @@ -17,8 +17,6 @@ type OrganizationTestSuite struct { sqlmock sqlmock.Sqlmock } -var mockedRows *sqlmock.Rows - var expectedOrg = Organization{ ID: 1, Name: "test organization", diff --git a/go-backend/db/recognition_moderation_test.go b/go-backend/db/recognition_moderation_test.go new file mode 100644 index 000000000..d8fabfa71 --- /dev/null +++ b/go-backend/db/recognition_moderation_test.go @@ -0,0 +1,86 @@ +package db + +import ( + "context" + "github.com/DATA-DOG/go-sqlmock" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "time" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including assertion methods. +type RecognitionModerationTestSuite struct { + suite.Suite + dbStore Storer + db *sqlx.DB + sqlmock sqlmock.Sqlmock +} + +func (suite *RecognitionModerationTestSuite) SetupTest() { + dbStore, dbConn, sqlmock := InitMockDB() + suite.dbStore = dbStore + suite.db = dbConn + suite.sqlmock = sqlmock + now = time.Now() + mockedRows = suite.getMockedRows(now) +} + +func (suite *RecognitionModerationTestSuite) TearDownTest() { + suite.db.Close() +} + +func (suite *RecognitionModerationTestSuite) getMockedRows(now time.Time) (mockedRows *sqlmock.Rows) { + mockedRows = suite.sqlmock.NewRows([]string{"id", "recognition_id", "is_inappropriate", "moderator_comment", "moderated_by", "moderated_at", "created_at", "updated_at"}). + AddRow(1, 1, true, "Test Comment", 1, now.Unix(), now, now) + return +} + +func (suite *RecognitionModerationTestSuite) TestCreateRecognitionModerationSuccess() { + isInappropriate := true + expectedRecognitionModeration := RecognitionModeration{ + ID: int64(1), + RecognitionID: int64(1), + IsInappropriate: &isInappropriate, + ModeratorComment: "Test Comment", + ModeratedBy: int64(1), + ModeratedAt: now.Unix(), + CreatedAt: now, + UpdatedAt: now, + } + + suite.sqlmock.ExpectQuery("INSERT INTO recognition_moderation"). + WithArgs(1, true, "Test Comment", 1, now.Unix(), sqlmock.AnyArg(), sqlmock.AnyArg()). + WillReturnRows(mockedRows) + + resp, err := suite.dbStore.CreateRecognitionModeration(context.Background(), expectedRecognitionModeration.ID, expectedRecognitionModeration) + + assert.Equal(suite.T(), expectedRecognitionModeration, resp) + assert.Nil(suite.T(), err) +} + +func (suite *RecognitionModerationTestSuite) TestCreateRecognitionModerationFailure() { + suite.db.Close() + + isInappropriate := true + expectedRecognitionModeration := RecognitionModeration{ + ID: int64(1), + RecognitionID: int64(1), + IsInappropriate: &isInappropriate, + ModeratorComment: "Test Comment", + ModeratedBy: int64(1), + ModeratedAt: now.Unix(), + CreatedAt: now, + UpdatedAt: now, + } + + suite.sqlmock.ExpectQuery("INSERT INTO recognition_moderation"). + WithArgs(1, true, "Test Comment", 1, now.Unix(), sqlmock.AnyArg(), sqlmock.AnyArg()). + WillReturnRows(mockedRows) + + resp, err := suite.dbStore.CreateRecognitionModeration(context.Background(), expectedRecognitionModeration.ID, expectedRecognitionModeration) + + assert.Equal(suite.T(), RecognitionModeration{}, resp) + assert.NotNil(suite.T(), err) +} diff --git a/go-backend/db/reported_recognition_test.go b/go-backend/db/reported_recognition_test.go new file mode 100644 index 000000000..e2e499ebf --- /dev/null +++ b/go-backend/db/reported_recognition_test.go @@ -0,0 +1,84 @@ +package db + +import ( + "context" + "github.com/DATA-DOG/go-sqlmock" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "time" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including assertion methods. +type ReportedRecognitionTestSuite struct { + suite.Suite + dbStore Storer + db *sqlx.DB + sqlmock sqlmock.Sqlmock +} + +func (suite *ReportedRecognitionTestSuite) SetupTest() { + dbStore, dbConn, sqlmock := InitMockDB() + suite.dbStore = dbStore + suite.db = dbConn + suite.sqlmock = sqlmock + now = time.Now() + mockedRows = suite.getMockedRows() +} + +func (suite *ReportedRecognitionTestSuite) TearDownTest() { + suite.db.Close() +} + +func (suite *ReportedRecognitionTestSuite) getMockedRows() (mockedRows *sqlmock.Rows) { + mockedRows = suite.sqlmock.NewRows([]string{"id", "recognition_id", "type_of_reporting", "reason_for_reporting", "reported_by", "reported_at", "created_at", "updated_at"}). + AddRow(1, 1, "fraud", "Test Reason", 1, now.Unix(), now, now) + return +} + +func (suite *ReportedRecognitionTestSuite) TestCreateReportedRecognitionSuccess() { + expectedReportedRecognition := ReportedRecognition{ + ID: int64(1), + RecognitionID: int64(1), + TypeOfReporting: "fraud", + ReasonForReporting: "Test Reason", + ReportedBy: int64(1), + ReportedAt: now.Unix(), + CreatedAt: now, + UpdatedAt: now, + } + + suite.sqlmock.ExpectQuery("INSERT INTO reported_recognitions"). + WithArgs(1, "fraud", "Test Reason", 1, now.Unix(), sqlmock.AnyArg(), sqlmock.AnyArg()). + WillReturnRows(mockedRows) + + resp, err := suite.dbStore.CreateReportedRecognition(context.Background(), expectedReportedRecognition.ID, expectedReportedRecognition) + + assert.Equal(suite.T(), expectedReportedRecognition, resp) + assert.Nil(suite.T(), err) +} + +func (suite *ReportedRecognitionTestSuite) TestCreateReportedRecognitionFailure() { + suite.db.Close() + + expectedReportedRecognition := ReportedRecognition{ + ID: int64(1), + RecognitionID: int64(1), + TypeOfReporting: "fraud", + ReasonForReporting: "Test Reason", + ReportedBy: int64(1), + ReportedAt: now.Unix(), + CreatedAt: now, + UpdatedAt: now, + } + + suite.sqlmock.ExpectQuery("INSERT INTO reported_recognitions"). + WithArgs(1, "fraud", "Test Reason", 1, now.Unix(), sqlmock.AnyArg(), sqlmock.AnyArg()). + WillReturnRows(mockedRows) + + resp, err := suite.dbStore.CreateReportedRecognition(context.Background(), expectedReportedRecognition.ID, expectedReportedRecognition) + + assert.Equal(suite.T(), ReportedRecognition{}, resp) + assert.NotNil(suite.T(), err) +} diff --git a/go-backend/service/common_http_test.go b/go-backend/service/common_http_test.go index b9af7f949..68333497c 100644 --- a/go-backend/service/common_http_test.go +++ b/go-backend/service/common_http_test.go @@ -14,6 +14,8 @@ func TestExampleTestSuite(t *testing.T) { suite.Run(t, new(OrganizationHandlerTestSuite)) suite.Run(t, new(RecognitionHi5HandlerTestSuite)) suite.Run(t, new(CoreValueHandlerTestSuite)) + suite.Run(t, new(ReportedRecognitionHandlerTestSuite)) + suite.Run(t, new(RecognitionModerationHandlerTestSuite)) } // path: is used to configure router path (eg: /users/{id}) diff --git a/go-backend/service/recognition_moderation_http.go b/go-backend/service/recognition_moderation_http.go index 2d9ce5166..3d0f37027 100644 --- a/go-backend/service/recognition_moderation_http.go +++ b/go-backend/service/recognition_moderation_http.go @@ -12,7 +12,7 @@ import ( func createRecognitionModerationHandler(deps Dependencies) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - userID := int64(1) //Extract for token + userID := int64(1) //Extract from token vars := mux.Vars(req) recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) diff --git a/go-backend/service/reported_recognition_http.go b/go-backend/service/reported_recognition_http.go index cb4fbefb3..6db5ec391 100644 --- a/go-backend/service/reported_recognition_http.go +++ b/go-backend/service/reported_recognition_http.go @@ -12,7 +12,7 @@ import ( func createReportedRecognitionHandler(deps Dependencies) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - userID := int64(1) //Extract for token + userID := int64(1) //Extract from token vars := mux.Vars(req) recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) From 5b80d0036e719ac121856bd0d8d85021de2434ca Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Tue, 16 Jun 2020 21:07:47 +0530 Subject: [PATCH 7/8] 1. Getting the userID from JWT Token. 2. Updated corresponding handler test cases. --- go-backend/service/common_http_test.go | 39 ++++++++++++++++++- .../service/recognition_moderation_http.go | 14 ++++++- .../recognition_moderation_http_test.go | 8 ++-- .../service/reported_recognition_http.go | 14 ++++++- .../service/reported_recognition_http_test.go | 12 +++--- go-backend/service/router.go | 13 +++++-- 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/go-backend/service/common_http_test.go b/go-backend/service/common_http_test.go index 68333497c..a6304dd51 100644 --- a/go-backend/service/common_http_test.go +++ b/go-backend/service/common_http_test.go @@ -1,15 +1,21 @@ package service import ( - "github.com/gorilla/mux" - "github.com/stretchr/testify/suite" "net/http" "net/http/httptest" "strings" "testing" + + jwtmiddleware "github.com/auth0/go-jwt-middleware" + jwt "github.com/dgrijalva/jwt-go" + "github.com/gorilla/mux" + "github.com/stretchr/testify/suite" + "github.com/urfave/negroni" + "joshsoftware/peerly/config" ) func TestExampleTestSuite(t *testing.T) { + config.Load("application_test") suite.Run(t, new(UsersHandlerTestSuite)) suite.Run(t, new(OrganizationHandlerTestSuite)) suite.Run(t, new(RecognitionHi5HandlerTestSuite)) @@ -35,3 +41,32 @@ func makeHTTPCall(method, path, requestURL, body string, handlerFunc http.Handle router.ServeHTTP(recorder, req) return } + +// path: is used to configure router path (eg: /users/{id}) +// requestURL: current request path (eg: /users/1) +func makeHTTPCallWithJWTMiddleware(method, path, requestURL, body string, handlerFunc http.HandlerFunc) (recorder *httptest.ResponseRecorder) { + // create a http request using the given parameters + JWTToken := "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTQ3MzYwNzcsImlhdCI6MTU5MjMxNjg3NywiaXNzIjoiam9zaHNvZnR3YXJlLmNvbSIsInN1YiI6IjIifQ._LLKR0aXg9QKBuvyPQebUgQKLQEOb80DDwxTb7fE7-A" + req, _ := http.NewRequest(method, requestURL, strings.NewReader(body)) + req.Header.Set("Authorization", JWTToken) + + // test recorder created for capturing api responses + recorder = httptest.NewRecorder() + + // create a router to serve the handler in test with the prepared request + router := mux.NewRouter() + jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ + ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { + return config.JWTKey(), nil + }, + SigningMethod: jwt.SigningMethodHS256, + }) + router.Handle(path, negroni.New( + negroni.HandlerFunc(jwtMiddleware.HandlerWithNext), + negroni.Wrap(http.HandlerFunc(handlerFunc)), + )).Methods(method) + + // serve the request and write the response to recorder + router.ServeHTTP(recorder, req) + return +} diff --git a/go-backend/service/recognition_moderation_http.go b/go-backend/service/recognition_moderation_http.go index 3d0f37027..a01ddce98 100644 --- a/go-backend/service/recognition_moderation_http.go +++ b/go-backend/service/recognition_moderation_http.go @@ -5,14 +5,24 @@ import ( "net/http" "strconv" + jwt "github.com/dgrijalva/jwt-go" "github.com/gorilla/mux" logger "github.com/sirupsen/logrus" + ae "joshsoftware/peerly/apperrors" "joshsoftware/peerly/db" ) func createRecognitionModerationHandler(deps Dependencies) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - userID := int64(1) //Extract from token + parsedToken := req.Context().Value("user").(*jwt.Token) + claims := parsedToken.Claims.(jwt.MapClaims) + + userID, err := strconv.Atoi(claims["sub"].(string)) + if err != nil { + logger.Error(ae.ErrJSONParseFail, "Error parsing JSON for token response", err) + ae.JSONError(rw, http.StatusInternalServerError, err) + return + } vars := mux.Vars(req) recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) @@ -33,7 +43,7 @@ func createRecognitionModerationHandler(deps Dependencies) http.HandlerFunc { }) return } - recognitionModeration.ModeratedBy = userID + recognitionModeration.ModeratedBy = int64(userID) ok, errFields := recognitionModeration.Validate() if !ok { diff --git a/go-backend/service/recognition_moderation_http_test.go b/go-backend/service/recognition_moderation_http_test.go index fa8cbfd79..6f4da7137 100644 --- a/go-backend/service/recognition_moderation_http_test.go +++ b/go-backend/service/recognition_moderation_http_test.go @@ -39,7 +39,7 @@ func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerat "comment": "Comment Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/review", "/recognitions/1/review", @@ -59,7 +59,7 @@ func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerat "comment": "Comment Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/review", "/recognitions/1/review", @@ -77,7 +77,7 @@ func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerat "comment": "Comment Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/review", "/recognitions/1/review", @@ -98,7 +98,7 @@ func (suite *RecognitionModerationHandlerTestSuite) TestCreateRecognitionModerat "reason": "Comment Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/review", "/recognitions/1/review", diff --git a/go-backend/service/reported_recognition_http.go b/go-backend/service/reported_recognition_http.go index 6db5ec391..d7124cee3 100644 --- a/go-backend/service/reported_recognition_http.go +++ b/go-backend/service/reported_recognition_http.go @@ -5,14 +5,24 @@ import ( "net/http" "strconv" + jwt "github.com/dgrijalva/jwt-go" "github.com/gorilla/mux" logger "github.com/sirupsen/logrus" + ae "joshsoftware/peerly/apperrors" "joshsoftware/peerly/db" ) func createReportedRecognitionHandler(deps Dependencies) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - userID := int64(1) //Extract from token + parsedToken := req.Context().Value("user").(*jwt.Token) + claims := parsedToken.Claims.(jwt.MapClaims) + + userID, err := strconv.Atoi(claims["sub"].(string)) + if err != nil { + logger.Error(ae.ErrJSONParseFail, "Error parsing JSON for token response", err) + ae.JSONError(rw, http.StatusInternalServerError, err) + return + } vars := mux.Vars(req) recognitionID, err := strconv.ParseInt(vars["recognition_id"], 10, 64) @@ -33,7 +43,7 @@ func createReportedRecognitionHandler(deps Dependencies) http.HandlerFunc { }) return } - reportedRecognition.ReportedBy = userID + reportedRecognition.ReportedBy = int64(userID) ok, errFields := reportedRecognition.Validate() if !ok { diff --git a/go-backend/service/reported_recognition_http_test.go b/go-backend/service/reported_recognition_http_test.go index b6a693a96..714cdf9be 100644 --- a/go-backend/service/reported_recognition_http_test.go +++ b/go-backend/service/reported_recognition_http_test.go @@ -38,7 +38,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionS "reason": "Reason Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", @@ -58,7 +58,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionW "reason": "Reason Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", @@ -77,7 +77,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionW "reason": "Reason Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", @@ -96,7 +96,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionW "reason": "Reason Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", @@ -115,7 +115,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionW "reason": "" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", @@ -136,7 +136,7 @@ func (suite *ReportedRecognitionHandlerTestSuite) TestCreateReportedRecognitionW "reason": "Reason Test" }` - recorder := makeHTTPCall( + recorder := makeHTTPCallWithJWTMiddleware( http.MethodPost, "/recognitions/{recognition_id:[0-9]+}/report", "/recognitions/1/report", diff --git a/go-backend/service/router.go b/go-backend/service/router.go index cc53bff28..827e55da1 100644 --- a/go-backend/service/router.go +++ b/go-backend/service/router.go @@ -4,12 +4,11 @@ import ( "fmt" "net/http" - "joshsoftware/peerly/config" - jwtmiddleware "github.com/auth0/go-jwt-middleware" jwt "github.com/dgrijalva/jwt-go" "github.com/gorilla/mux" "github.com/urfave/negroni" + "joshsoftware/peerly/config" ) const ( @@ -41,10 +40,16 @@ func InitRouter(deps Dependencies) (router *mux.Router) { router.HandleFunc("/organisations/{organisation_id:[0-9]+}/core_values/{id:[0-9]+}", updateCoreValueHandler(deps)).Methods(http.MethodPut).Headers(versionHeader, v1) //reported recognition - router.HandleFunc("/recognitions/{recognition_id:[0-9]+}/report", createReportedRecognitionHandler(deps)).Methods(http.MethodPost).Headers(versionHeader, v1) + router.Handle("/recognitions/{recognition_id:[0-9]+}/report", negroni.New( + negroni.HandlerFunc(jwtMiddleware.HandlerWithNext), + negroni.Wrap(http.HandlerFunc(createReportedRecognitionHandler(deps))), + )).Methods(http.MethodPost).Headers(versionHeader, v1) //recognition moderation - router.HandleFunc("/recognitions/{recognition_id:[0-9]+}/review", createRecognitionModerationHandler(deps)).Methods(http.MethodPost).Headers(versionHeader, v1) + router.Handle("/recognitions/{recognition_id:[0-9]+}/review", negroni.New( + negroni.HandlerFunc(jwtMiddleware.HandlerWithNext), + negroni.Wrap(http.HandlerFunc(createRecognitionModerationHandler(deps))), + )).Methods(http.MethodPost).Headers(versionHeader, v1) //users router.HandleFunc("/users", listUsersHandler(deps)).Methods(http.MethodGet).Headers(versionHeader, v1) From 1157c00c62177a4dfbe28178ef290cb6f3bd7853 Mon Sep 17 00:00:00 2001 From: pradipdkshirsagar Date: Wed, 17 Jun 2020 09:07:53 +0530 Subject: [PATCH 8/8] Get dynamic jwt token for testing --- go-backend/service/common_http_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go-backend/service/common_http_test.go b/go-backend/service/common_http_test.go index a6304dd51..47bc1bd66 100644 --- a/go-backend/service/common_http_test.go +++ b/go-backend/service/common_http_test.go @@ -45,10 +45,12 @@ func makeHTTPCall(method, path, requestURL, body string, handlerFunc http.Handle // path: is used to configure router path (eg: /users/{id}) // requestURL: current request path (eg: /users/1) func makeHTTPCallWithJWTMiddleware(method, path, requestURL, body string, handlerFunc http.HandlerFunc) (recorder *httptest.ResponseRecorder) { + // create jwt token with userID + JWTToken, _ := newJWT(1) + // create a http request using the given parameters - JWTToken := "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTQ3MzYwNzcsImlhdCI6MTU5MjMxNjg3NywiaXNzIjoiam9zaHNvZnR3YXJlLmNvbSIsInN1YiI6IjIifQ._LLKR0aXg9QKBuvyPQebUgQKLQEOb80DDwxTb7fE7-A" req, _ := http.NewRequest(method, requestURL, strings.NewReader(body)) - req.Header.Set("Authorization", JWTToken) + req.Header.Set("Authorization", "Bearer " + JWTToken) // test recorder created for capturing api responses recorder = httptest.NewRecorder()