Skip to content

Commit 11e189c

Browse files
authored
Merge pull request #89 from v79/86-move-generated-folder-to-new-s3-bucket
86 move generated folder to new s3 bucket
2 parents c69e3d6 + d3ed701 commit 11e189c

File tree

82 files changed

+2658
-1433
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2658
-1433
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ ImageProcessor/.gradle/buildOutputCleanup/buildOutputCleanup.lock
4848
ImageProcessor/.gradle/buildOutputCleanup/cache.properties
4949
ImageProcessor/.gradle/buildOutputCleanup/outputFiles.bin
5050
ImageProcessor/.gradle/vcs-1/gc.properties
51+
Web/build/*
52+
Web/node_modules/*
53+
/DevDiary/*

.idea/.gitignore

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/codeStyles/Project.xml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

API/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ plugins {
1010
}
1111

1212
group = "org.liamjd.cantilever"
13-
version = "0.0.11"
13+
version = "0.0.12"
1414

1515
repositories {
1616
mavenCentral()

API/src/main/kotlin/org/liamjd/cantilever/api/API.kt

+175-135
Large diffs are not rendered by default.

API/src/main/kotlin/org/liamjd/cantilever/api/controllers/APIController.kt

+31-25
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ import com.charleskorn.kaml.Yaml
44
import kotlinx.serialization.json.Json
55
import org.koin.core.component.KoinComponent
66
import org.koin.core.component.inject
7-
import org.liamjd.cantilever.api.models.APIResult
87
import org.liamjd.cantilever.common.MimeType
9-
import org.liamjd.cantilever.common.S3_KEY
108
import org.liamjd.cantilever.models.CantileverProject
119
import org.liamjd.cantilever.models.ContentTree
12-
import org.liamjd.cantilever.routing.ResponseEntity
1310
import org.liamjd.cantilever.services.S3Service
1411

15-
abstract class APIController(val sourceBucket: String) : KoinComponent {
12+
abstract class APIController(val sourceBucket: String, val generationBucket: String) : KoinComponent {
1613

1714
val s3Service: S3Service by inject()
1815
val contentTree: ContentTree = ContentTree()
@@ -21,43 +18,52 @@ abstract class APIController(val sourceBucket: String) : KoinComponent {
2118
/**
2219
* Load the content tree from the S3 bucket
2320
*/
24-
fun loadContentTree(): Boolean {
25-
if (s3Service.objectExists(S3_KEY.metadataKey, sourceBucket)) {
26-
info("Reading metadata.json from bucket $sourceBucket")
27-
contentTree.clear()
28-
val metadata = s3Service.getObjectAsString(S3_KEY.metadataKey, sourceBucket)
29-
val newTree = Json.decodeFromString(ContentTree.serializer(), metadata)
30-
contentTree.items.addAll(newTree.items)
31-
contentTree.templates.addAll(newTree.templates)
32-
contentTree.statics.addAll(newTree.statics)
33-
contentTree.images.addAll(newTree.images)
34-
return true
35-
} else {
36-
warn("No '${S3_KEY.metadataKey}' file found in bucket $sourceBucket; please regenerate new empty tree")
21+
fun loadContentTree(domain: String): Boolean {
22+
val metadataKey = "$domain/metadata.json"
23+
try {
24+
if (s3Service.objectExists(metadataKey, generationBucket)) {
25+
info("Reading $metadataKey from bucket $generationBucket")
26+
contentTree.clear()
27+
val metadata = s3Service.getObjectAsString(metadataKey, generationBucket)
28+
val newTree = Json.decodeFromString(ContentTree.serializer(), metadata)
29+
contentTree.items.addAll(newTree.items)
30+
contentTree.templates.addAll(newTree.templates)
31+
contentTree.statics.addAll(newTree.statics)
32+
contentTree.images.addAll(newTree.images)
33+
return true
34+
} else {
35+
warn("No '$metadataKey' file found in bucket $generationBucket; please regenerate new empty tree")
36+
return false
37+
}
38+
} catch (e: Exception) {
39+
error("Error reading $metadataKey from bucket $generationBucket: ${e.message}")
3740
return false
3841
}
3942
}
4043

4144
/**
4245
* Save the content tree to the S3 bucket after a change
4346
*/
44-
fun saveContentTree() {
45-
info("Saving content tree to bucket $sourceBucket")
47+
fun saveContentTree(domain: String) {
48+
val metadataKey =
49+
"$domain/metadata.json"
50+
info("Saving content tree $metadataKey to bucket $generationBucket")
4651
val json = Json { prettyPrint = true }
4752
val metadata = json.encodeToString(ContentTree.serializer(), contentTree)
48-
s3Service.putObjectAsString(S3_KEY.metadataKey, sourceBucket, metadata, MimeType.json.toString())
53+
s3Service.putObjectAsString(metadataKey, generationBucket, metadata, MimeType.json.toString())
4954
}
5055

5156
/**
5257
* Load the project definition 'cantilever.yaml' from the S3 bucket
5358
*/
54-
fun loadProjectDefinition() {
55-
if (s3Service.objectExists(S3_KEY.projectKey, sourceBucket)) {
56-
info("Reading cantilever.yaml from bucket $sourceBucket")
57-
val projectYaml = s3Service.getObjectAsString(S3_KEY.projectKey, sourceBucket)
59+
fun loadProjectDefinition(domain: String) {
60+
val projectKey = "$domain.yaml"
61+
if (s3Service.objectExists(projectKey, sourceBucket)) {
62+
info("Reading $projectKey from bucket $sourceBucket")
63+
val projectYaml = s3Service.getObjectAsString(projectKey, sourceBucket)
5864
project = Yaml.default.decodeFromString(CantileverProject.serializer(), projectYaml)
5965
} else {
60-
error("No '${S3_KEY.projectKey}' file found in bucket $sourceBucket!")
66+
error("No '$projectKey' file found in bucket $sourceBucket!")
6167
}
6268
}
6369

API/src/main/kotlin/org/liamjd/cantilever/api/controllers/GeneratorController.kt

+57-19
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import java.nio.charset.Charset
2020
/**
2121
* Handle routes relating to document generation. Mostly this will be done by sending messages to the appropriate queues.
2222
*/
23-
class GeneratorController(sourceBucket: String) : KoinComponent, APIController(sourceBucket) {
23+
class GeneratorController(sourceBucket: String, generationBucket: String) : KoinComponent, APIController(sourceBucket, generationBucket) {
2424

2525
companion object {
2626
const val error_NO_RESPONSE = "No response received for message"
@@ -40,16 +40,17 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
4040
val requestKey = request.pathParameters["srcKey"]
4141
?: return ResponseEntity.badRequest(body = APIResult.Error("No srcKey provided"))
4242
var srcKey = ""
43+
val projectKeyHeader = request.headers["cantilever-project-domain"]!!
4344
try {
44-
loadContentTree()
45+
loadContentTree(projectKeyHeader)
4546
if (requestKey == "*") {
4647
info("GeneratorController: Received request to regenerate all pages")
4748
val pages = contentTree.items.filterIsInstance<ContentNode.PageNode>()
4849
var count = 0
4950
if (pages.isNotEmpty()) {
5051
pages.forEach { page ->
5152
val sourceString = s3Service.getObjectAsString(page.srcKey, sourceBucket)
52-
val msgResponse = queuePageRegeneration(page.srcKey, sourceString)
53+
val msgResponse = queuePageRegeneration(projectKeyHeader, page.srcKey, sourceString)
5354
if (msgResponse != null) {
5455
count++
5556
} else {
@@ -65,12 +66,12 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
6566
srcKey = URLDecoder.decode(requestKey, Charset.defaultCharset())
6667
info("GeneratorController: Received request to regenerate page '$srcKey'")
6768
val sourceString = s3Service.getObjectAsString(srcKey, sourceBucket)
68-
queuePageRegeneration(srcKey, sourceString)
69+
queuePageRegeneration(projectKeyHeader, srcKey, sourceString)
6970
return ResponseEntity.ok(body = APIResult.Success(value = "Regenerated page '$requestKey'"))
7071
}
7172
} catch (nske: NoSuchKeyException) {
7273
error("${nske.message} for key $srcKey")
73-
return ResponseEntity.notFound(body = APIResult.Error(message = "Could not find page with key '$srcKey'"))
74+
return ResponseEntity.notFound(body = APIResult.Error(statusText = "Could not find page with key '$srcKey'"))
7475
} catch (e: Exception) {
7576
error("Error generating page: ${e.message}")
7677
return ResponseEntity.serverError(body = APIResult.Error("Error generating page: ${e.message}"))
@@ -86,8 +87,9 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
8687
fun generatePost(request: Request<Unit>): ResponseEntity<APIResult<String>> {
8788
val requestKey = request.pathParameters["srcKey"]
8889
var srcKey = ""
90+
val projectKeyHeader = request.headers["cantilever-project-domain"]!!
8991
try {
90-
loadContentTree()
92+
loadContentTree(projectKeyHeader)
9193
if (requestKey == "*") {
9294
info("GeneratorController: Received request to regenerate all posts")
9395
val posts = contentTree.items.filterIsInstance<ContentNode.PostNode>()
@@ -96,7 +98,11 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
9698
posts.forEach { post ->
9799
val sourceString = s3Service.getObjectAsString(post.srcKey, sourceBucket)
98100
val postSrcKey = post.srcKey.removePrefix(postsPrefix)
99-
val msgResponse = queuePostRegeneration(postSrcKey, sourceString)
101+
val msgResponse = queuePostRegeneration(
102+
postSrcKey = postSrcKey,
103+
sourceString = sourceString,
104+
projectDomain = projectKeyHeader
105+
)
100106
if (msgResponse != null) {
101107
count++
102108
} else {
@@ -113,13 +119,18 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
113119
info("GeneratorController: Received request to regenerate post '$srcKey'")
114120
val sourceString = s3Service.getObjectAsString(srcKey, sourceBucket)
115121
val postSrcKey = srcKey.removePrefix(postsPrefix)
116-
queuePostRegeneration(postSrcKey, sourceString)
122+
queuePostRegeneration(
123+
postSrcKey = postSrcKey,
124+
sourceString = sourceString,
125+
projectDomain = projectKeyHeader
126+
)
117127
return ResponseEntity.ok(body = APIResult.Success(value = "Regenerated post '$requestKey'"))
118128
}
119129
} catch (nske: NoSuchKeyException) {
120130
error("${nske.message} for key $srcKey")
121-
return ResponseEntity.notFound(body = APIResult.Error(message = "Could not find post with key '$srcKey'"))
131+
return ResponseEntity.notFound(body = APIResult.Error(statusText = "Could not find post with key '$srcKey'"))
122132
} catch (e: Exception) {
133+
error("Error generating post: ${e.javaClass}: ${e.message}")
123134
return ResponseEntity.serverError(body = APIResult.Error("Error generating post: ${e.message}"))
124135
}
125136
}
@@ -136,23 +147,30 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
136147
body = APIResult.Error("Regeneration of all templates is not supported.")
137148
)
138149
}
139-
info("ENCODED: GeneratorController received request to regenerate pages based on template '$requestKey'")
150+
val projectKeyHeader = request.headers["cantilever-project-domain"]!!
140151
// TODO: https://github.com/v79/Cantilever/issues/26 this only works for HTML handlebars templates, i.e. those whose file names end in ".index.html" in the "templates" folder.
141152
// Also, annoying that I have to double-decode this.
153+
// And I need to strip off the domain from the requestKey
142154
val templateKey =
143-
URLDecoder.decode(URLDecoder.decode(requestKey, Charset.defaultCharset()), Charset.defaultCharset())
155+
URLDecoder.decode(URLDecoder.decode(requestKey, Charset.defaultCharset()), Charset.defaultCharset()).substringAfter(
156+
"$projectKeyHeader/"
157+
)
144158
info(
145-
"DOUBLE DECODED: GeneratorController received request to regenerate pages based on template '$templateKey'"
159+
"Received request to regenerate pages based on template '$templateKey'"
146160
)
147161
var count = 0
148162

149163
// We don't know if the template is for a Page or a Post. This is less than ideal as I have to check both. But I could short-circuit the second check if the first one succeeds?
150164
try {
151-
loadContentTree()
165+
loadContentTree(projectKeyHeader)
152166
contentTree.getPagesForTemplate(templateKey).forEach { page ->
153167
info("Regenerating page ${page.srcKey} because it has template ${page.templateKey}")
154168
val pageSource = s3Service.getObjectAsString(page.srcKey, sourceBucket)
155-
val response = queuePageRegeneration(page.srcKey, pageSource)
169+
val response = queuePageRegeneration(
170+
pageSrcKey = page.srcKey,
171+
sourceString = pageSource,
172+
projectDomain = projectKeyHeader
173+
)
156174
if (response != null) {
157175
count++
158176
} else {
@@ -163,7 +181,11 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
163181
contentTree.getPostsForTemplate(templateKey).forEach { post ->
164182
info("Regenerating post ${post.srcKey} because it has template ${post.templateKey}")
165183
val postSource = s3Service.getObjectAsString(post.srcKey, sourceBucket)
166-
val msgResponse = queuePostRegeneration(post.srcKey, postSource)
184+
val msgResponse = queuePostRegeneration(
185+
postSrcKey = post.srcKey,
186+
sourceString = postSource,
187+
projectDomain = projectKeyHeader
188+
)
167189
if (msgResponse != null) {
168190
count++
169191
} else {
@@ -194,10 +216,18 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
194216
/**
195217
* Send a message to the markdown queue for a Page
196218
*/
197-
private fun queuePageRegeneration(pageSrcKey: String, sourceString: String): SendMessageResponse? {
219+
private fun queuePageRegeneration(
220+
pageSrcKey: String,
221+
sourceString: String,
222+
projectDomain: String
223+
): SendMessageResponse? {
198224
// extract page model
199225
val pageMode = ContentMetaDataBuilder.PageBuilder.buildFromSourceString(sourceString, pageSrcKey)
200-
val msgBody = MarkdownSQSMessage.PageUploadMsg(pageMode, sourceString)
226+
val msgBody = MarkdownSQSMessage.PageUploadMsg(
227+
projectDomain = projectDomain,
228+
metadata = pageMode,
229+
markdownText = sourceString
230+
)
201231
return sqsService.sendMarkdownMessage(
202232
toQueue = markdownQueue, body = msgBody,
203233
messageAttributes = createStringAttribute("sourceType", SOURCE_TYPE.Pages.folder)
@@ -207,14 +237,22 @@ class GeneratorController(sourceBucket: String) : KoinComponent, APIController(s
207237
/**
208238
* Send a message to the markdown queue for a Post
209239
*/
210-
private fun queuePostRegeneration(postSrcKey: String, sourceString: String): SendMessageResponse? {
240+
private fun queuePostRegeneration(
241+
postSrcKey: String,
242+
sourceString: String,
243+
projectDomain: String
244+
): SendMessageResponse? {
211245
// extract post model
212246
val metadata =
213247
ContentMetaDataBuilder.PostBuilder.buildFromSourceString(sourceString.getFrontMatter(), postSrcKey)
214248
// extract body
215249
val markdownBody = sourceString.stripFrontMatter()
216250

217-
val msgBody = MarkdownSQSMessage.PostUploadMsg(metadata, markdownBody)
251+
val msgBody = MarkdownSQSMessage.PostUploadMsg(
252+
projectDomain = projectDomain,
253+
metadata = metadata,
254+
markdownText = markdownBody
255+
)
218256
return sqsService.sendMarkdownMessage(
219257
toQueue = markdownQueue, body = msgBody,
220258
messageAttributes = createStringAttribute("sourceType", SOURCE_TYPE.Posts.folder)

0 commit comments

Comments
 (0)