Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Commit

Permalink
Add http endpoint to soft delete a document
Browse files Browse the repository at this point in the history
  • Loading branch information
vxio committed Sep 23, 2020
1 parent 07a27b0 commit f07cf45
Show file tree
Hide file tree
Showing 9 changed files with 356 additions and 2 deletions.
38 changes: 38 additions & 0 deletions api/client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,44 @@ paths:
application/json:
schema:
$ref: 'https://raw.githubusercontent.com/moov-io/api/master/openapi-common.yaml#/components/schemas/Error'
delete:
description: Remove a customer's document
operationId: deleteCustomerDocument
parameters:
- name: X-Request-ID
in: header
description: Optional requestID allows application developer to trace requests through the systems logs
example: rs4f9915
schema:
type: string
- name: customerID
in: path
description: ID of the customer that owns the document
required: true
schema:
example: e210a9d6-d755-4455-9bd2-9577ea7e1081
type: string
style: simple
- name: documentID
in: path
description: ID of the document
required: true
schema:
example: 9577ea7e1081
type: string
style: simple
responses:
"204":
description: Customer's document successfully deleted
'400':
description: Failed to delete customer's document, see error(s)
content:
application/json:
schema:
$ref: 'https://raw.githubusercontent.com/moov-io/api/master/openapi-common.yaml#/components/schemas/Error'
summary: Delete a customer's document
tags:
- Customers
/customers/{customerID}/ofac:
get:
tags: [Customers]
Expand Down
4 changes: 4 additions & 0 deletions internal/database/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ var (
"create_namespace_configuration",
`create table namespace_configuration(namespace varchar(40) primary key not null, legal_entity varchar(40) not null, primary_account varchar(40) not null);`,
),
execsql(
"add_deleted_at__to__documents",
"alter table documents add column deleted_at datetime;",
),
)
)

Expand Down
2 changes: 1 addition & 1 deletion internal/database/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var (
),
execsql(
"create_documents",
`create table if not exists documents(document_id primary key, customer_id, type, content_type, uploaded_at datetime);`,
`create table if not exists documents(document_id primary key, customer_id, type, content_type, uploaded_at datetime, deleted_at datetime);`,
),
execsql(
"create_disclaimers",
Expand Down
1 change: 1 addition & 0 deletions pkg/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Class | Method | HTTP request | Description
*CustomersApi* | [**DecryptAccountNumber**](docs/CustomersApi.md#decryptaccountnumber) | **Post** /customers/{customerID}/accounts/{accountID}/decrypt | Decrypt Account Number
*CustomersApi* | [**DeleteCustomer**](docs/CustomersApi.md#deletecustomer) | **Delete** /customers/{customerID} | Delete Customer by ID
*CustomersApi* | [**DeleteCustomerAccount**](docs/CustomersApi.md#deletecustomeraccount) | **Delete** /customers/{customerID}/accounts | Delete Customer Account
*CustomersApi* | [**DeleteCustomerDocument**](docs/CustomersApi.md#deletecustomerdocument) | **Delete** /customers/{customerID}/documents/{documentID} | Delete a customer's document
*CustomersApi* | [**GetAccountValidation**](docs/CustomersApi.md#getaccountvalidation) | **Get** /customers/{customerID}/accounts/{accountID}/validations/{validationID} | Get Account Validation
*CustomersApi* | [**GetCustomer**](docs/CustomersApi.md#getcustomer) | **Get** /customers/{customerID} | Retrieve customer
*CustomersApi* | [**GetCustomerAccountByID**](docs/CustomersApi.md#getcustomeraccountbyid) | **Get** /customers/{customerID}/accounts/{accountID} | Get Customer Account by ID
Expand Down
44 changes: 44 additions & 0 deletions pkg/client/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,50 @@ paths:
tags:
- Customers
/customers/{customerID}/documents/{documentID}:
delete:
description: Remove a customer's document
operationId: deleteCustomerDocument
parameters:
- description: Optional requestID allows application developer to trace requests
through the systems logs
example: rs4f9915
explode: false
in: header
name: X-Request-ID
required: false
schema:
type: string
style: simple
- description: ID of the customer that owns the document
explode: false
in: path
name: customerID
required: true
schema:
example: e210a9d6-d755-4455-9bd2-9577ea7e1081
type: string
style: simple
- description: ID of the document
explode: false
in: path
name: documentID
required: true
schema:
example: 9577ea7e1081
type: string
style: simple
responses:
"204":
description: Customer's document successfully deleted
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: Failed to delete customer's document, see error(s)
summary: Delete a customer's document
tags:
- Customers
get:
description: Retrieve the referenced document
operationId: getCustomerDocumentContents
Expand Down
89 changes: 89 additions & 0 deletions pkg/client/api_customers.go
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,95 @@ func (a *CustomersApiService) DeleteCustomerAccount(ctx _context.Context, custom
return localVarHTTPResponse, nil
}

// DeleteCustomerDocumentOpts Optional parameters for the method 'DeleteCustomerDocument'
type DeleteCustomerDocumentOpts struct {
XRequestID optional.String
}

/*
DeleteCustomerDocument Delete a customer's document
Remove a customer's document
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @param customerID ID of the customer that owns the document
* @param documentID ID of the document
* @param optional nil or *DeleteCustomerDocumentOpts - Optional Parameters:
* @param "XRequestID" (optional.String) - Optional requestID allows application developer to trace requests through the systems logs
*/
func (a *CustomersApiService) DeleteCustomerDocument(ctx _context.Context, customerID string, documentID string, localVarOptionals *DeleteCustomerDocumentOpts) (*_nethttp.Response, error) {
var (
localVarHTTPMethod = _nethttp.MethodDelete
localVarPostBody interface{}
localVarFormFileName string
localVarFileName string
localVarFileBytes []byte
)

// create path and map variables
localVarPath := a.client.cfg.BasePath + "/customers/{customerID}/documents/{documentID}"
localVarPath = strings.Replace(localVarPath, "{"+"customerID"+"}", _neturl.QueryEscape(parameterToString(customerID, "")), -1)

localVarPath = strings.Replace(localVarPath, "{"+"documentID"+"}", _neturl.QueryEscape(parameterToString(documentID, "")), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := _neturl.Values{}
localVarFormParams := _neturl.Values{}

// to determine the Content-Type header
localVarHTTPContentTypes := []string{}

// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}

// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}

// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
if localVarOptionals != nil && localVarOptionals.XRequestID.IsSet() {
localVarHeaderParams["X-Request-ID"] = parameterToString(localVarOptionals.XRequestID.Value(), "")
}
r, err := a.client.prepareRequest(ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
if err != nil {
return nil, err
}

localVarHTTPResponse, err := a.client.callAPI(r)
if err != nil || localVarHTTPResponse == nil {
return localVarHTTPResponse, err
}

localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body)
localVarHTTPResponse.Body.Close()
if err != nil {
return localVarHTTPResponse, err
}

if localVarHTTPResponse.StatusCode >= 300 {
newErr := GenericOpenAPIError{
body: localVarBody,
error: localVarHTTPResponse.Status,
}
if localVarHTTPResponse.StatusCode == 400 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarHTTPResponse, newErr
}
newErr.model = v
}
return localVarHTTPResponse, newErr
}

return localVarHTTPResponse, nil
}

// GetAccountValidationOpts Optional parameters for the method 'GetAccountValidation'
type GetAccountValidationOpts struct {
XRequestID optional.String
Expand Down
48 changes: 48 additions & 0 deletions pkg/client/docs/CustomersApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Method | HTTP request | Description
[**DecryptAccountNumber**](CustomersApi.md#DecryptAccountNumber) | **Post** /customers/{customerID}/accounts/{accountID}/decrypt | Decrypt Account Number
[**DeleteCustomer**](CustomersApi.md#DeleteCustomer) | **Delete** /customers/{customerID} | Delete Customer by ID
[**DeleteCustomerAccount**](CustomersApi.md#DeleteCustomerAccount) | **Delete** /customers/{customerID}/accounts | Delete Customer Account
[**DeleteCustomerDocument**](CustomersApi.md#DeleteCustomerDocument) | **Delete** /customers/{customerID}/documents/{documentID} | Delete a customer's document
[**GetAccountValidation**](CustomersApi.md#GetAccountValidation) | **Get** /customers/{customerID}/accounts/{accountID}/validations/{validationID} | Get Account Validation
[**GetCustomer**](CustomersApi.md#GetCustomer) | **Get** /customers/{customerID} | Retrieve customer
[**GetCustomerAccountByID**](CustomersApi.md#GetCustomerAccountByID) | **Get** /customers/{customerID}/accounts/{accountID} | Get Customer Account by ID
Expand Down Expand Up @@ -413,6 +414,53 @@ No authorization required
[[Back to README]](../README.md)


## DeleteCustomerDocument

> DeleteCustomerDocument(ctx, customerID, documentID, optional)
Delete a customer's document

Remove a customer's document

### Required Parameters


Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc.
**customerID** | **string**| ID of the customer that owns the document |
**documentID** | **string**| ID of the document |
**optional** | ***DeleteCustomerDocumentOpts** | optional parameters | nil if no parameters

### Optional Parameters

Optional parameters are passed through a pointer to a DeleteCustomerDocumentOpts struct


Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------


**xRequestID** | **optional.String**| Optional requestID allows application developer to trace requests through the systems logs |

### Return type

(empty response body)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: Not defined
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints)
[[Back to Model list]](../README.md#documentation-for-models)
[[Back to README]](../README.md)


## GetAccountValidation

> AccountValidationResponse GetAccountValidation(ctx, customerID, accountID, validationID, optional)
Expand Down
40 changes: 39 additions & 1 deletion pkg/customers/documents.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

"github.com/moov-io/base"
moovhttp "github.com/moov-io/base/http"

"github.com/moov-io/customers/pkg/client"
"github.com/moov-io/customers/pkg/route"

Expand All @@ -36,6 +37,7 @@ func AddDocumentRoutes(logger log.Logger, r *mux.Router, repo DocumentRepository
r.Methods("GET").Path("/customers/{customerID}/documents").HandlerFunc(getCustomerDocuments(logger, repo))
r.Methods("POST").Path("/customers/{customerID}/documents").HandlerFunc(uploadCustomerDocument(logger, repo, bucketFactory))
r.Methods("GET").Path("/customers/{customerID}/documents/{documentId}").HandlerFunc(retrieveRawDocument(logger, repo, bucketFactory))
r.Methods("DELETE").Path("/customers/{customerID}/documents/{documentId}").HandlerFunc(deleteCustomerDocument(logger, repo))
}

func getDocumentID(w http.ResponseWriter, r *http.Request) string {
Expand Down Expand Up @@ -198,13 +200,37 @@ func retrieveRawDocument(logger log.Logger, repo DocumentRepository, bucketFacto
}
}

func deleteCustomerDocument(logger log.Logger, repo DocumentRepository) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w = route.Responder(logger, w, r)
requestID := moovhttp.GetRequestID(r)

customerID, documentID := route.GetCustomerID(w, r), getDocumentID(w, r)
if customerID == "" || documentID == "" {
return
}

err := repo.deleteCustomerDocument(customerID, documentID)
if err != nil {
moovhttp.Problem(w, fmt.Errorf("deleting document: %v", err))
logger.Log("documents", fmt.Sprintf("error deleting document=%s for customer=%s: %v", documentID, customerID, err), "requestID", requestID)
return
}

logger.Log("documents", fmt.Sprintf("successfully deleted document=%s for customer=%s", documentID, customerID), "requestID", requestID)

w.WriteHeader(http.StatusNoContent)
}
}

func makeDocumentKey(customerID, documentId string) string {
return fmt.Sprintf("customer-%s-document-%s", customerID, documentId)
}

type DocumentRepository interface {
getCustomerDocuments(customerID string) ([]*client.Document, error)
writeCustomerDocument(customerID string, doc *client.Document) error
deleteCustomerDocument(customerID string, documentID string) error
}

type sqlDocumentRepository struct {
Expand All @@ -219,7 +245,7 @@ func NewDocumentRepo(logger log.Logger, db *sql.DB) DocumentRepository {
}
}
func (r *sqlDocumentRepository) getCustomerDocuments(customerID string) ([]*client.Document, error) {
query := `select document_id, type, content_type, uploaded_at from documents where customer_id = ?`
query := `select document_id, type, content_type, uploaded_at from documents where customer_id = ? and deleted_at is null`
stmt, err := r.db.Prepare(query)
if err != nil {
return nil, fmt.Errorf("getCustomerDocuments: prepare %v", err)
Expand Down Expand Up @@ -256,3 +282,15 @@ func (r *sqlDocumentRepository) writeCustomerDocument(customerID string, doc *cl
}
return nil
}

func (r *sqlDocumentRepository) deleteCustomerDocument(customerID string, documentID string) error {
query := `update documents set deleted_at = ? where customer_id = ? and document_id = ? and deleted_at is null;`
stmt, err := r.db.Prepare(query)
if err != nil {
return err
}
defer stmt.Close()

_, err = stmt.Exec(time.Now(), customerID, documentID)
return err
}
Loading

0 comments on commit f07cf45

Please sign in to comment.