Skip to content

Commit

Permalink
Merge branch 'main' into 78-bug-user-survey-responses-not-accessible
Browse files Browse the repository at this point in the history
* main:
  update version to 1.11.0
  [ID-79]Consolidate the information, and make it accessible with a single API call (#81)

# Conflicts:
#	CHANGELOG.md
  • Loading branch information
Stefan Vitanov committed Nov 6, 2024
2 parents 844121a + c301edc commit da76ae2
Show file tree
Hide file tree
Showing 19 changed files with 318 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- User survey responses not accessible [#78](https://github.com/rokwire/surveys-building-block/issues/78)
## [1.11.0] - 2024-10-07
### Added
- Consolidate the information, and make it accessible with a single API call [#79](https://github.com/rokwire/surveys-building-block/issues/79)

## [1.10.3] - 2024-08-21
### Fixed
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Patches for **Surveys Building Block** in this repository will only be applied t

| Version | Supported |
| ------- | ------------------ |
| 1.10.3 | :white_check_mark: |
| < 1.10.3 | :x: |
| 1.11.0 | :white_check_mark: |
| < 1.11.0 | :x: |

## Reporting a Bug or Vulnerability

Expand Down
5 changes: 5 additions & 0 deletions core/app_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ func (a appClient) CreateSurveyAlert(surveyAlert model.SurveyAlert) error {
return nil
}

// GetUserData returns surveys matching the provided query
func (a appClient) GetUserData(orgID string, appID string, userID *string) (*model.UserData, error) {
return a.app.shared.getUserData(orgID, appID, userID)
}

// newAppClient creates new appClient
func newAppClient(app *Application) appClient {
return appClient{app: app}
Expand Down
66 changes: 66 additions & 0 deletions core/app_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,72 @@ func (a appShared) hasAttendedEvent(orgID string, appID string, eventID string,
return false, nil
}

func (a appShared) getUserData(orgID string, appID string, userID *string) (*model.UserData, error) {
var serveyUserData []model.SurveysUserData
var surveyResponseUserData []model.SurveysResponseUserData

// Create channels for data and error handling
surveysChan := make(chan []model.Survey, 1)
surveysErrChan := make(chan error, 1)
surveyResponsesChan := make(chan []model.SurveyResponse, 1)
surveyResponsesErrChan := make(chan error, 1)

// Fetch surveys asynchronously
go func() {
surveys, err := a.app.storage.GetSurveysLight(orgID, appID, userID)
if err != nil {
surveysErrChan <- err
return
}
surveysChan <- surveys
}()

// Fetch survey responses asynchronously
go func() {
surveysResponses, err := a.app.storage.GetSurveyResponses(&orgID, &appID, userID, nil, nil, nil, nil, nil, nil)
if err != nil {
surveyResponsesErrChan <- err
return
}
surveyResponsesChan <- surveysResponses
}()

// Wait for both operations to complete or return an error
var surveys []model.Survey
var surveysResponses []model.SurveyResponse

for i := 0; i < 2; i++ {
select {
case err := <-surveysErrChan:
return nil, err
case err := <-surveyResponsesErrChan:
return nil, err
case surveys = <-surveysChan:
// Handle the surveys data when received
case surveysResponses = <-surveyResponsesChan:
// Handle the survey responses data when received
}
}

// Process the surveys data
for _, s := range surveys {
survey := model.SurveysUserData{ID: s.ID, CreatorID: s.CreatorID, AppID: s.AppID, AccountID: s.CreatorID,
OrgID: s.OrgID, Title: s.Title, Type: s.Type}
serveyUserData = append(serveyUserData, survey)
}

// Process the survey responses data
for _, sr := range surveysResponses {
surveyResponse := model.SurveysResponseUserData{ID: sr.ID, UserID: sr.UserID, AppID: sr.AppID, AccountID: sr.UserID,
OrgID: sr.OrgID, Title: sr.Survey.Title}
surveyResponseUserData = append(surveyResponseUserData, surveyResponse)
}

// Return the user data after all data has been fetched and processed
userData := model.UserData{SurveyUserData: &serveyUserData, SurveyResponseUserData: &surveyResponseUserData}
return &userData, nil
}

// newAppShared creates new appShared
func newAppShared(app *Application) appShared {
return appShared{app: app}
Expand Down
2 changes: 2 additions & 0 deletions core/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Shared interface {

isEventAdmin(orgID string, appID string, eventID string, userID string, externalIDs map[string]string) (bool, error)
hasAttendedEvent(orgID string, appID string, eventID string, userID string, externalIDs map[string]string) (bool, error)

getUserData(orgID string, appID string, userID *string) (*model.UserData, error)
}

// Core exposes Core APIs for the driver adapters
Expand Down
3 changes: 3 additions & 0 deletions core/interfaces/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ type Client interface {

// Survey Alerts
CreateSurveyAlert(surveyAlert model.SurveyAlert) error

// User data
GetUserData(orgID string, appID string, userID *string) (*model.UserData, error)
}

// Admin exposes administrative APIs for the driver adapters
Expand Down
2 changes: 2 additions & 0 deletions core/interfaces/driven.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Storage interface {

GetSurvey(id string, orgID string, appID string) (*model.Survey, error)
GetSurveys(orgID string, appID string, creatorID *string, surveyIDs []string, surveyTypes []string, calendarEventID string, limit *int, offset *int, filter *model.SurveyTimeFilter, public *bool, archived *bool, completed *bool) ([]model.Survey, error)
GetSurveysLight(orgID string, appID string, creatorID *string) ([]model.Survey, error)

CreateSurvey(survey model.Survey) (*model.Survey, error)
UpdateSurvey(survey model.Survey, admin bool) error
DeleteSurvey(id string, orgID string, appID string, creatorID string, admin bool) error
Expand Down
32 changes: 31 additions & 1 deletion core/interfaces/mocks/Storage.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions core/model/surveys.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,30 @@ type SurveyTimeFilterRequest struct {
EndTimeAfter *string `json:"end_time_after"`
EndTimeBefore *string `json:"end_time_before"`
}

// SurveysUserData represents user data for surveys
type SurveysUserData struct {
ID string `json:"id" bson:"_id"`
CreatorID string `json:"creator_id" bson:"creator_id"`
AppID string `json:"app_id"`
AccountID string `json:"account_id"`
OrgID string `json:"org_id"`
Title string `json:"title"`
Type string `json:"type"`
}

// SurveysResponseUserData represents user data for surveys responses
type SurveysResponseUserData struct {
ID string `json:"id"`
UserID string `json:"user_id"`
AppID string `json:"app_id"`
AccountID string `json:"account_id"`
OrgID string `json:"org_id"`
Title string `json:"title"`
}

// UserData represents user data
type UserData struct {
SurveyUserData *[]SurveysUserData `json:"survey"`
SurveyResponseUserData *[]SurveysResponseUserData `json:"survey_responses"`
}
20 changes: 20 additions & 0 deletions driven/storage/adapter_surveys.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,26 @@ func (a *Adapter) GetSurveys(orgID string, appID string, creatorID *string, surv
return results, nil
}

// GetSurveysLight gets matching surveys
func (a *Adapter) GetSurveysLight(orgID string, appID string, creatorID *string) ([]model.Survey, error) {
filter := bson.D{
{Key: "org_id", Value: orgID},
{Key: "app_id", Value: appID},
}

if creatorID != nil {
filter = append(filter, bson.E{Key: "creator_id", Value: *creatorID})
}

var results []model.Survey
err := a.db.surveys.Find(a.context, filter, &results, nil)
if err != nil {
return nil, err
}

return results, nil
}

// CreateSurvey creates a poll
func (a *Adapter) CreateSurvey(survey model.Survey) (*model.Survey, error) {
_, err := a.db.surveys.InsertOne(a.context, survey)
Expand Down
1 change: 1 addition & 0 deletions driver/web/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (a Adapter) Start() {
mainRouter.HandleFunc("/survey-responses", a.wrapFunc(a.clientAPIsHandler.deleteSurveyResponses, a.auth.client.User)).Methods("DELETE")
mainRouter.HandleFunc("/survey-alerts", a.wrapFunc(a.clientAPIsHandler.createSurveyAlert, a.auth.client.User)).Methods("POST")
mainRouter.HandleFunc("/creator/surveys", a.wrapFunc(a.clientAPIsHandler.getCreatorSurveys, a.auth.client.User)).Methods("GET")
mainRouter.HandleFunc("/user-data", a.wrapFunc(a.clientAPIsHandler.getUserData, a.auth.client.User)).Methods("GET")

// Admin APIs
adminRouter := mainRouter.PathPrefix("/admin").Subrouter()
Expand Down
14 changes: 14 additions & 0 deletions driver/web/apis_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,20 @@ func (h ClientAPIsHandler) getCreatorSurveys(l *logs.Log, r *http.Request, claim
return l.HTTPResponseSuccessJSON(data)
}

func (h ClientAPIsHandler) getUserData(l *logs.Log, r *http.Request, claims *tokenauth.Claims) logs.HTTPResponse {
resData, err := h.app.Client.GetUserData(claims.OrgID, claims.AppID, &claims.Subject)
if err != nil {
return l.HTTPResponseErrorAction(logutils.ActionGet, model.TypeSurvey, nil, err, http.StatusInternalServerError, true)
}

data, err := json.Marshal(resData)
if err != nil {
return l.HTTPResponseErrorAction(logutils.ActionMarshal, logutils.TypeResponseBody, nil, err, http.StatusInternalServerError, false)
}

return l.HTTPResponseSuccessJSON(data)
}

// NewClientAPIsHandler creates new client API handler instance
func NewClientAPIsHandler(app *core.Application) ClientAPIsHandler {
return ClientAPIsHandler{app: app}
Expand Down
69 changes: 68 additions & 1 deletion driver/web/docs/gen/def.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: 3.0.3
info:
title: Rokwire Surveys Building Block API
description: Surveys Building Block API Documentation
version: 1.10.3
version: 1.11.0
servers:
- url: 'https://api.rokwire.illinois.edu/surveys'
description: Production server
Expand Down Expand Up @@ -712,6 +712,30 @@ paths:
description: Unauthorized
'500':
description: Internal error
/api/user-data:
get:
tags:
- Client
summary: Retrieves surveys
description: |
Retrieves surveys matching the provided query
security:
- bearerAuth: []
responses:
'200':
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UserData'
'400':
description: Bad request
'401':
description: Unauthorized
'500':
description: Internal error
/api/admin/configs:
get:
tags:
Expand Down Expand Up @@ -1855,6 +1879,49 @@ components:
type: string
params:
type: object
UserData:
type: object
properties:
survey:
type: array
items:
type: object
properties:
id:
type: string
org_id:
type: string
app_id:
type: string
creator_id:
type: string
account_id:
type: string
context:
type: object
title:
type: string
type:
type: string
survey_responses:
type: array
items:
type: object
properties:
id:
type: string
org_id:
type: string
app_id:
type: string
creator_id:
type: string
account_id:
type: string
context:
type: object
title:
type: string
_admin_req_update-configs:
required:
- type
Expand Down
4 changes: 3 additions & 1 deletion driver/web/docs/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: 3.0.3
info:
title: Rokwire Surveys Building Block API
description: Surveys Building Block API Documentation
version: 1.10.3
version: 1.11.0
servers:
- url: 'https://api.rokwire.illinois.edu/surveys'
description: Production server
Expand Down Expand Up @@ -45,6 +45,8 @@ paths:
$ref: "./resources/client/survey-alerts.yaml"
/api/creator/surveys:
$ref: "./resources/client/creator/surveys.yaml"
/api/user-data:
$ref: "./resources/client/user-data.yaml"

# Admin
/api/admin/configs:
Expand Down
23 changes: 23 additions & 0 deletions driver/web/docs/resources/client/user-data.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
get:
tags:
- Client
summary: Retrieves surveys
description: |
Retrieves surveys matching the provided query
security:
- bearerAuth: []
responses:
200:
description: Success
content:
application/json:
schema:
type: array
items:
$ref: "../../schemas/surveys/UserData.yaml"
400:
description: Bad request
401:
description: Unauthorized
500:
description: Internal error
Loading

0 comments on commit da76ae2

Please sign in to comment.