Skip to content

Commit acd4a06

Browse files
authored
Merge pull request #5 from nikhilsharma8193/option-to-delete
Added option to delete stored file from Amazon S3.
2 parents 5657caa + 1a819d9 commit acd4a06

File tree

6 files changed

+127
-7
lines changed

6 files changed

+127
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A plugin for multi purpose file upload functionality for Grails 3 application. T
44
to the following destinations:
55

66
1. To the local server or the local system
7-
2. To the Amazon S3 storage (coming soon)
7+
2. To the Amazon S3 storage (can be deleted as well)
88
3. To the Rackspace cloud storage (coming soon)
99

1010
## Installation

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ buildscript {
99
}
1010
}
1111

12-
version "0.0.5"
12+
version "0.0.6"
1313
group "com.wizpanda.plugins"
1414

1515
apply plugin:"eclipse"

grails-app/domain/com/wizpanda/file/StoredFile.groovy

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.wizpanda.file
22

3+
import grails.util.Holders
4+
35
class StoredFile {
46

57
String originalName
@@ -9,4 +11,23 @@ class StoredFile {
911
Long size
1012
Date uploadedOn = new Date()
1113
Map meta = [:]
14+
15+
FileUploadService getFileUploadService() {
16+
FileUploadService fileUploadService = Holders.getApplicationContext()['fileUploadService']
17+
18+
if (!fileUploadService) {
19+
log.warn "FileUploadService bean not injected!"
20+
return
21+
}
22+
23+
return fileUploadService
24+
}
25+
26+
void remove() {
27+
fileUploadService?.delete(this)
28+
}
29+
30+
void cloneFile(String newGroupName) {
31+
fileUploadService?.cloneFile(this, newGroupName)
32+
}
1233
}

grails-app/services/com/wizpanda/file/FileUploadService.groovy

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@ class FileUploadService {
2323
return services.get(groupName).instance().save(file)
2424
}
2525

26+
void delete(StoredFile file) {
27+
if (!file) {
28+
log.warn 'StoredFile is null.'
29+
return
30+
}
31+
32+
services.get(file.groupName).instance().delete(file)
33+
}
34+
35+
void cloneFile(StoredFile file, String newGroupName) {
36+
if (!file) {
37+
log.warn 'StoredFile cannot be null.'
38+
return
39+
}
40+
41+
if (!newGroupName) {
42+
log.warn 'New Group Name cannot be null.'
43+
return
44+
}
45+
46+
services.get(newGroupName).instance().cloneStoredFile(file, newGroupName)
47+
}
48+
2649
@PostConstruct
2750
void verifyConfig() {
2851
//log.debug "Verifying all service"

src/main/groovy/com/wizpanda/file/api/AmazonS3Api.groovy

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
package com.wizpanda.file.api
22

3+
import com.wizpanda.file.ConfigHelper
34
import com.wizpanda.file.StoredFile
45
import com.wizpanda.file.service.AmazonS3UploaderService
56
import grails.util.Environment
67
import grails.util.GrailsStringUtils
8+
import groovy.util.logging.Slf4j
79
import org.jclouds.ContextBuilder
810
import org.jclouds.aws.s3.AWSS3Client
911
import org.jclouds.blobstore.BlobStore
1012
import org.jclouds.blobstore.BlobStoreContext
13+
import org.jclouds.http.HttpResponseException
14+
import org.jclouds.s3.domain.CannedAccessPolicy
1115
import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl
16+
import org.jclouds.s3.options.CopyObjectOptions
1217

1318
import javax.activation.MimetypesFileTypeMap
1419

20+
@Slf4j
1521
abstract class AmazonS3Api extends AbstractStorageApi {
1622

1723
BlobStore blobStore
@@ -20,15 +26,15 @@ abstract class AmazonS3Api extends AbstractStorageApi {
2026
AmazonS3UploaderService service
2127

2228
void authenticate() {
23-
println service.accessKey
24-
println service.accessSecret
2529
context = ContextBuilder.newBuilder("aws-s3")
2630
.credentials(service.accessKey, service.accessSecret)
2731
.buildView(BlobStoreContext.class)
28-
println "Context created ${context.class}"
32+
33+
log.info "Context created ${context.class}"
2934

3035
blobStore = context.getBlobStore()
31-
println "BlobStore ${blobStore.class}"
36+
37+
log.info "BlobStore ${blobStore.class}"
3238

3339
// Storing wrapped Api of S3Client with Apache JCloud
3440
client = context.unwrap().getApi()
@@ -55,6 +61,15 @@ abstract class AmazonS3Api extends AbstractStorageApi {
5561
return name + "." + extension
5662
}
5763

64+
@Override
65+
String getFileName(StoredFile file) {
66+
String name = UUID.randomUUID().toString()
67+
String originalFileName = file.originalName
68+
String extension = GrailsStringUtils.substringAfterLast(originalFileName, ".")
69+
70+
return name + "." + extension
71+
}
72+
5873
String getContainerName() {
5974
String name = service.container
6075
if (Environment.current != Environment.PRODUCTION) {
@@ -75,6 +90,62 @@ abstract class AmazonS3Api extends AbstractStorageApi {
7590

7691
@Override
7792
void deleteNativeFile(StoredFile file) {
78-
// TODO implement me
93+
String container = this.containerName
94+
String fileName = file.name
95+
96+
log.info "Deleting file ${file} with name ${fileName} from container ${container}."
97+
98+
this.authenticate()
99+
100+
if (!client.objectExists(container, fileName)) {
101+
log.warn "File not present in the S3 bucket, deleting the Stored file instance."
102+
103+
file.delete()
104+
this.close()
105+
106+
return
107+
}
108+
109+
client.deleteObject(container, fileName)
110+
file.delete()
111+
112+
this.close()
113+
}
114+
115+
@Override
116+
StoredFile cloneStoredFile(StoredFile file, String newGroupName) {
117+
StoredFile clonedFile = new StoredFile()
118+
clonedFile.originalName = file.originalName
119+
clonedFile.groupName = newGroupName
120+
clonedFile.size = file.size
121+
clonedFile.name = getFileName(file)
122+
123+
String currentContainer = ConfigHelper.getGroup(file.groupName).container ?:
124+
ConfigHelper.getFlatConfig("global.amazon.container")
125+
126+
String newContainer = getContainerName()
127+
128+
CopyObjectOptions fileOptions = new CopyObjectOptions()
129+
// For now using the same policy of original file, it gets changed to private scope if not overridden.
130+
fileOptions.overrideAcl(CannedAccessPolicy.PUBLIC_READ)
131+
132+
try {
133+
this.authenticate()
134+
client.copyObject(currentContainer, file.name, newContainer, clonedFile.name, fileOptions)
135+
clonedFile.url = client.getObject(newContainer, clonedFile.name, null).metadata.uri
136+
137+
this.gormFile = clonedFile
138+
this.gormFile.uploadedOn = new Date()
139+
140+
this.saveGORMFile()
141+
142+
log.info "Successfully cloned StoredFile: ${file} as ${this.gormFile}"
143+
144+
return this.gormFile
145+
} catch (HttpResponseException hre) {
146+
log.warn 'Could not copy StoredFile!', hre
147+
} finally {
148+
this.close()
149+
}
79150
}
80151
}

src/main/groovy/com/wizpanda/file/api/StorageApi.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ interface StorageApi {
1717

1818
String getFileName(File file)
1919

20+
String getFileName(StoredFile file)
21+
2022
StoredFile saveGORMFile() throws FileUploadException
2123

2224
/**
@@ -35,4 +37,7 @@ interface StorageApi {
3537
StoredFile save(MultipartFile multipartFile) throws FileUploadException
3638

3739
void delete(StoredFile file)
40+
41+
// Used to clone an instance of StoredFile and get the new StoredFile instance.
42+
StoredFile cloneStoredFile(StoredFile file, String newGroupName)
3843
}

0 commit comments

Comments
 (0)