Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#32] Delete survey responses for deleted tenant app memberships #33

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
go-version: '1.22'
check-latest: true

- name: Build
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Delete survey responses for deleted tenant app memberships [#32](https://github.com/rokwire/surveys-building-block/issues/32)

## [1.3.0] - 2023-09-20
### Added
- Reintroduce survey responses admin API [#27](https://github.com/rokwire/surveys-building-block/issues/27)
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.20-alpine as builder
FROM golang:1.22-alpine as builder

ENV CGO_ENABLED=0

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The API documentation is available here: https://api-dev.rokwire.illinois.edu/su
### Prerequisites
MongoDB v4.4+

Go v1.20+
Go v1.22+

### Environment variables
The following Environment variables are supported. The service will not start unless those marked as Required are supplied.
Expand Down
2 changes: 1 addition & 1 deletion core/app_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (a appClient) DeleteSurveyResponse(id string, orgID string, appID string, u

// DeleteSurveyResponses deletes the survey responses matching the provided filters
func (a appClient) DeleteSurveyResponses(orgID string, appID string, userID string, surveyIDs []string, surveyTypes []string, startDate *time.Time, endDate *time.Time) error {
return a.app.storage.DeleteSurveyResponses(orgID, appID, userID, surveyIDs, surveyTypes, startDate, endDate)
return a.app.storage.DeleteSurveyResponses(orgID, appID, []string{userID}, surveyIDs, surveyTypes, startDate, endDate, false)
}

// Survey Alerts
Expand Down
88 changes: 84 additions & 4 deletions core/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import (
"application/core/interfaces"
"application/core/model"
"application/utils"

"github.com/rokwire/core-auth-library-go/v3/authservice"
"github.com/rokwire/core-auth-library-go/v3/authutils"
"github.com/rokwire/core-auth-library-go/v3/coreservice"
"github.com/rokwire/logging-library-go/v2/errors"
"github.com/rokwire/logging-library-go/v2/logs"
"github.com/rokwire/logging-library-go/v2/logutils"
Expand All @@ -38,8 +41,9 @@

// Application represents the core application code based on hexagonal architecture
type Application struct {
version string
build string
version string
build string
serviceID string

Default interfaces.Default // expose to the drivers adapters
Client interfaces.Client // expose to the drivers adapters
Expand All @@ -55,13 +59,19 @@
storage interfaces.Storage
notifications interfaces.Notifications
calendar interfaces.Calendar

coreService *coreservice.CoreService
}

// Start starts the core part of the application
func (a *Application) Start() {
//set storage listener
storageListener := storageListener{app: a}
a.storage.RegisterStorageListener(&storageListener)

if a.coreService != nil {
a.coreService.StartDeletedMembershipsTimer()

Check failure on line 73 in core/application.go

View workflow job for this annotation

GitHub Actions / build

a.coreService.StartDeletedMembershipsTimer undefined (type *coreservice.CoreService has no field or method StartDeletedMembershipsTimer)
}
}

// GetEnvConfigs retrieves the cached database env configs
Expand All @@ -77,9 +87,79 @@
return model.GetConfigData[model.EnvConfigData](*config)
}

func (a *Application) handleDeletedMemberships(deleted []coreservice.DeletedOrgAppMemberships) error {

Check failure on line 90 in core/application.go

View workflow job for this annotation

GitHub Actions / build

undefined: coreservice.DeletedOrgAppMemberships
for _, orgAppMemberships := range deleted {
noContextAccountIDs := make([]string, 0)
for _, context := range orgAppMemberships.Memberships {
if context.Context != nil {
retainData, err := a.getRetainSurveyResponsesData(context.Context)
if err != nil {
err = errors.WrapErrorAction(logutils.ActionGet, "retain survey responses data", &logutils.FieldArgs{"org_id": orgAppMemberships.OrgID, "app_id": orgAppMemberships.AppID, "account_id": context.AccountID}, err)
a.logger.Error(err.Error())
continue
}
if retainData == nil {
continue
}
err = a.storage.DeleteSurveyResponsesExcept(orgAppMemberships.OrgID, orgAppMemberships.AppID, context.AccountID, retainData.SurveyIDs, retainData.SurveyTypes, nil, nil, true)
if err != nil && a.logger != nil {
err = errors.WrapErrorAction(logutils.ActionDelete, model.TypeSurveyResponse, &logutils.FieldArgs{"org_id": orgAppMemberships.OrgID, "app_id": orgAppMemberships.AppID}, err)
a.logger.Error(err.Error())
}
} else {
noContextAccountIDs = append(noContextAccountIDs, context.AccountID)
}
}

if len(noContextAccountIDs) > 0 {
err := a.storage.DeleteSurveyResponses(orgAppMemberships.OrgID, orgAppMemberships.AppID, noContextAccountIDs, nil, nil, nil, nil, true)
if err != nil && a.logger != nil {
err = errors.WrapErrorAction(logutils.ActionDelete, model.TypeSurveyResponse, &logutils.FieldArgs{"org_id": orgAppMemberships.OrgID, "app_id": orgAppMemberships.AppID}, err)
a.logger.Error(err.Error())
}
}
}

return nil
}

func (a *Application) getRetainSurveyResponsesData(context map[string]interface{}) (*retainSurveyResponsesData, error) {
surveyResponseContext, err := utils.JSONConvert[deleteSurveyResponsesContext](context)
if err != nil {
return nil, errors.WrapErrorAction(logutils.ActionParse, "delete survey responses context", nil, err)
}
if surveyResponseContext == nil {
return nil, nil
}

return &surveyResponseContext.RetainResponses, nil
}

type deleteSurveyResponsesContext struct {
RetainResponses retainSurveyResponsesData `json:"retain_responses"`
}

type retainSurveyResponsesData struct {
SurveyIDs []string `json:"survey_ids"`
SurveyTypes []string `json:"survey_types"`
}

// NewApplication creates new Application
func NewApplication(version string, build string, storage interfaces.Storage, notifications interfaces.Notifications, calendar interfaces.Calendar, logger *logs.Logger) *Application {
application := Application{version: version, build: build, storage: storage, notifications: notifications, calendar: calendar, logger: logger}
func NewApplication(version string, build string, serviceID string, storage interfaces.Storage, notifications interfaces.Notifications, calendar interfaces.Calendar,
serviceAccountManager *authservice.ServiceAccountManager, logger *logs.Logger) *Application {

application := Application{version: version, build: build, serviceID: serviceID, storage: storage, notifications: notifications, calendar: calendar, logger: logger}

var err error
if serviceAccountManager != nil {
deletedAccountsConfig := coreservice.DeletedMembershipsConfig{

Check failure on line 155 in core/application.go

View workflow job for this annotation

GitHub Actions / build

undefined: coreservice.DeletedMembershipsConfig
Callback: application.handleDeletedMemberships,
}
application.coreService, err = coreservice.NewCoreService(serviceAccountManager, &deletedAccountsConfig, logger)
if err != nil && logger != nil {
logger.Errorf("error creating core service: %v", err)
}
}

//add the drivers ports/interfaces
application.Default = newAppDefault(&application)
Expand Down
2 changes: 1 addition & 1 deletion core/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const (
func buildTestApplication(storage interfaces.Storage) *core.Application {
loggerOpts := logs.LoggerOpts{SuppressRequests: logs.NewStandardHealthCheckHTTPRequestProperties(serviceID + "/version")}
logger := logs.NewLogger(serviceID, &loggerOpts)
return core.NewApplication("1.1.1", "build", storage, nil, nil, logger)
return core.NewApplication("1.1.1", "build", serviceID, storage, nil, nil, nil, logger)
}

func TestApplication_Start(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion core/interfaces/driven.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ type Storage interface {
CreateSurveyResponse(surveyResponse model.SurveyResponse) (*model.SurveyResponse, error)
UpdateSurveyResponse(surveyResponse model.SurveyResponse) error
DeleteSurveyResponse(id string, orgID string, appID string, userID string) error
DeleteSurveyResponses(orgID string, appID string, userID string, surveyIDs []string, surveyTypes []string, startDate *time.Time, endDate *time.Time) error
DeleteSurveyResponses(orgID string, appID string, userIDs []string, surveyIDs []string, surveyTypes []string, startDate *time.Time, endDate *time.Time, ignoreMissingError bool) error
DeleteSurveyResponsesExcept(orgID string, appID string, userID string, surveyIDs []string, surveyTypes []string, startDate *time.Time, endDate *time.Time, ignoreMissingError bool) error

GetAlertContacts(orgID string, appID string) ([]model.AlertContact, error)
GetAlertContact(id string, orgID string, appID string) (*model.AlertContact, error)
Expand Down
Loading
Loading