Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
cdaa29f07d | |||
5ce29aa86e | |||
fc5f29eaed | |||
4d89e45c7b | |||
a132f6540c | |||
409469c624 | |||
e7eb82ceb6 | |||
b3ad5016fb | |||
c89668031c | |||
62f68a25a5 | |||
3b77006381 | |||
5e81284220 | |||
0e16d42eaf | |||
58b00cbdb0 | |||
f551165a82 |
14
.elasticbeanstalk/config.yml
Normal file
14
.elasticbeanstalk/config.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
branch-defaults:
|
||||||
|
master:
|
||||||
|
environment: new-life-songs-env
|
||||||
|
global:
|
||||||
|
application_name: new-life-songs
|
||||||
|
branch: null
|
||||||
|
default_ec2_keyname: id_jdb@jdb-maingear
|
||||||
|
default_platform: Tomcat 8 Java 8
|
||||||
|
default_region: us-west-2
|
||||||
|
profile: eb-cli
|
||||||
|
repository: null
|
||||||
|
sc: git
|
||||||
|
deploy:
|
||||||
|
artifact: build/ROOT.war
|
8
README.md
Normal file
8
README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# New Life Songs Database
|
||||||
|
|
||||||
|
This is Jonathan's database of worship songs performed at New Life Austin. The
|
||||||
|
service lives online at http://newlifesongs.jdbernard.com
|
||||||
|
|
||||||
|
API Documentation is [maintained online with the service](http://newlifesongs.jdbernard.com/doc/api/v1/).
|
||||||
|
|
||||||
|
You can also view the [annotated source code](https://doc.jdb-labs.com/new-life-songs/current/).
|
90
build.gradle
90
build.gradle
@ -5,8 +5,6 @@ apply plugin: "maven"
|
|||||||
apply plugin: "war"
|
apply plugin: "war"
|
||||||
apply plugin: "jetty"
|
apply plugin: "jetty"
|
||||||
|
|
||||||
apply from: 'shell.gradle'
|
|
||||||
|
|
||||||
group = "com.jdbernard"
|
group = "com.jdbernard"
|
||||||
|
|
||||||
version = new ProjectVersion()
|
version = new ProjectVersion()
|
||||||
@ -18,33 +16,32 @@ repositories {
|
|||||||
mavenCentral() }
|
mavenCentral() }
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'ch.qos.logback:logback-classic:1.1.2'
|
compile 'ch.qos.logback:logback-classic:1.1.8'
|
||||||
compile 'ch.qos.logback:logback-core:1.1.2'
|
compile 'ch.qos.logback:logback-core:1.1.8'
|
||||||
compile 'com.impossibl.pgjdbc-ng:pgjdbc-ng:0.3'
|
compile 'com.impossibl.pgjdbc-ng:pgjdbc-ng:0.6'
|
||||||
compile 'com.lambdaworks:scrypt:1.4.0'
|
compile 'com.lambdaworks:scrypt:1.4.0'
|
||||||
compile 'com.zaxxer:HikariCP-java6:2.3.2'
|
compile 'com.zaxxer:HikariCP:2.5.1'
|
||||||
compile 'javax:javaee-api:7.0'
|
compile 'javax:javaee-api:7.0'
|
||||||
compile 'javax.ws.rs:javax.ws.rs-api:2.0.1'
|
compile 'javax.ws.rs:javax.ws.rs-api:2.0.1'
|
||||||
compile 'joda-time:joda-time:2.7'
|
compile 'joda-time:joda-time:2.7'
|
||||||
compile 'org.codehaus.groovy:groovy-all:2.3.6'
|
compile 'org.codehaus.groovy:groovy-all:2.4.7'
|
||||||
compile 'org.slf4j:slf4j-api:1.7.10'
|
compile 'org.slf4j:slf4j-api:1.7.22'
|
||||||
runtime 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.3.2'
|
runtime 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.3.2'
|
||||||
runtime 'org.glassfish.jersey.containers:jersey-container-servlet:2.16'
|
runtime 'org.glassfish.jersey.containers:jersey-container-servlet:2.16'
|
||||||
runtime 'org.glassfish.jersey.media:jersey-media-json-jackson:2.16'
|
runtime 'org.glassfish.jersey.media:jersey-media-json-jackson:2.16'
|
||||||
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
|
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
|
||||||
|
|
||||||
testCompile 'com.jdbernard:jdb-util:3.4'
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testRuntime 'com.h2database:h2:1.4.186'
|
testRuntime 'com.h2database:h2:1.4.186'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
war {
|
war {
|
||||||
from "resources/webapp"
|
from "resources/webapp"
|
||||||
from "build/webapp"
|
from "build/webapp"
|
||||||
|
version = project.version.releaseVersion
|
||||||
filter(ReplaceTokens, tokens: [version: version])
|
filter(ReplaceTokens, tokens: [version: version])
|
||||||
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
|
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
|
||||||
version = project.version.releaseVersion
|
|
||||||
webInf { from 'resources/main/WEB-INF' }
|
webInf { from 'resources/main/WEB-INF' }
|
||||||
exclude "**/.*.swp", "**/.sass-cache"
|
exclude "**/.*.swp", "**/.sass-cache"
|
||||||
}
|
}
|
||||||
@ -53,9 +50,9 @@ test { testLogging { events 'failed' } }
|
|||||||
|
|
||||||
task testWar(type: War) {
|
task testWar(type: War) {
|
||||||
from 'resources/webapp'
|
from 'resources/webapp'
|
||||||
|
version = project.version.releaseVersion
|
||||||
filter(ReplaceTokens, tokens: [version: version])
|
filter(ReplaceTokens, tokens: [version: version])
|
||||||
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
|
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
|
||||||
version = project.version.releaseVersion
|
|
||||||
webInf { from 'resources/test/WEB-INF' }
|
webInf { from 'resources/test/WEB-INF' }
|
||||||
classifier 'test' }
|
classifier 'test' }
|
||||||
|
|
||||||
@ -70,34 +67,34 @@ task compileScss(
|
|||||||
|
|
||||||
war.dependsOn compileScss
|
war.dependsOn compileScss
|
||||||
testWar.dependsOn compileScss
|
testWar.dependsOn compileScss
|
||||||
|
|
||||||
// ## Build Versioning task
|
// ## Build Versioning task
|
||||||
task incrementBuildNumber(
|
task incrementBuildNumber(
|
||||||
group: 'versioning',
|
group: 'versioning',
|
||||||
description: "Increment the project's build number."
|
description: "Increment the project's build number."
|
||||||
) << { ++version.build }
|
) { doLast { ++version.build } }
|
||||||
|
|
||||||
task incrementMinorNumber(
|
task incrementMinorNumber(
|
||||||
group: 'versioning',
|
group: 'versioning',
|
||||||
description: "Increment the project's minor version number."
|
description: "Increment the project's minor version number."
|
||||||
) << { ++version.minor }
|
) { doLast { ++version.minor } }
|
||||||
|
|
||||||
task incrementMajorNumber(
|
task incrementMajorNumber(
|
||||||
group: 'versioning',
|
group: 'versioning',
|
||||||
description: "Increment the project's major version number."
|
description: "Increment the project's major version number."
|
||||||
) << { ++version.major }
|
) { doLast { ++version.major } }
|
||||||
|
|
||||||
task markReleaseBuild(
|
task markReleaseBuild(
|
||||||
group: 'versioning',
|
group: 'versioning',
|
||||||
description: "Mark this version of the project as a release version."
|
description: "Mark this version of the project as a release version."
|
||||||
) << { version.release = true }
|
) { doLast { version.release = true } }
|
||||||
|
|
||||||
war.dependsOn << incrementBuildNumber
|
war.dependsOn << incrementBuildNumber
|
||||||
testWar.dependsOn << incrementBuildNumber
|
testWar.dependsOn << incrementBuildNumber
|
||||||
|
|
||||||
// ## Custom tasks for local deployment
|
// ## Custom tasks for local deployment
|
||||||
|
|
||||||
task deployLocal(dependsOn: ['build']) << {
|
task deployLocal(dependsOn: ['build']) { doLast {
|
||||||
def warName = "${project.name}-${version.releaseVersion}.war"
|
def warName = "${project.name}-${version.releaseVersion}.war"
|
||||||
def jettyHome = System.getenv("JETTY_HOME")
|
def jettyHome = System.getenv("JETTY_HOME")
|
||||||
def deployedWar = new File("$jettyHome/webapps/$warName")
|
def deployedWar = new File("$jettyHome/webapps/$warName")
|
||||||
@ -106,16 +103,29 @@ task deployLocal(dependsOn: ['build']) << {
|
|||||||
copy {
|
copy {
|
||||||
from "build/libs"
|
from "build/libs"
|
||||||
into "$jettyHome/webapps"
|
into "$jettyHome/webapps"
|
||||||
include warName } }
|
include warName } } }
|
||||||
|
|
||||||
task killJettyLocal() << {
|
task deployProd(dependsOn: ['build']) { doLast {
|
||||||
|
def warName = "${project.name}-${version.releaseVersion}.war"
|
||||||
|
def artifactName = "ROOT.war"
|
||||||
|
|
||||||
|
copy {
|
||||||
|
from "build/libs"
|
||||||
|
into "build"
|
||||||
|
include warName
|
||||||
|
rename warName, artifactName }
|
||||||
|
|
||||||
|
shell_("eb", "deploy", "-l", "${project.name}-${version}")
|
||||||
|
} }
|
||||||
|
|
||||||
|
task killJettyLocal() { doLast {
|
||||||
def pidFile = new File(System.properties['user.home'] + "/temp/jetty.pid")
|
def pidFile = new File(System.properties['user.home'] + "/temp/jetty.pid")
|
||||||
|
|
||||||
println "Killing old Jetty instance."
|
println "Killing old Jetty instance."
|
||||||
shell_("sh", "-c", 'kill $(jps -l | grep start.jar | cut -f 1 -d " ")') }
|
shell_("sh", "-c", 'kill $(jps -l | grep start.jar | cut -f 1 -d " ")') } }
|
||||||
|
|
||||||
task localJetty(dependsOn: ['killJettyLocal', 'deployLocal']) << {
|
task localJetty(dependsOn: ['killJettyLocal', 'deployLocal']) { doLast {
|
||||||
spawn(["java", "-jar", "start.jar"], new File(jettyHome)) }
|
spawn(["java", "-jar", "start.jar"], new File(jettyHome)) } }
|
||||||
|
|
||||||
// ## Project Version
|
// ## Project Version
|
||||||
class ProjectVersion {
|
class ProjectVersion {
|
||||||
@ -167,3 +177,37 @@ class ProjectVersion {
|
|||||||
this[it] = props[it] ? props[it] as int : 0 }
|
this[it] = props[it] ? props[it] as int : 0 }
|
||||||
release = Boolean.parseBoolean(props["version.release"]) }
|
release = Boolean.parseBoolean(props["version.release"]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ## Utility methods for working with processes.
|
||||||
|
|
||||||
|
def shell_(List<String> cmd) { shell(cmd, null, false) }
|
||||||
|
def shell_(String... cmd) { shell(cmd, null, false) }
|
||||||
|
def shell(String... cmd) { shell(cmd, null, true) }
|
||||||
|
|
||||||
|
def shell(List<String> cmd, File workingDir, boolean checkExit) {
|
||||||
|
shell(cmd as String[], workingDir, checkExit) }
|
||||||
|
|
||||||
|
def shell(String[] cmd, File workingDir, boolean checkExit) {
|
||||||
|
def pb = new ProcessBuilder(cmd)
|
||||||
|
if (workingDir) pb.directory(workingDir)
|
||||||
|
def process = pb.start()
|
||||||
|
process.waitForProcessOutput(System.out, System.err)
|
||||||
|
|
||||||
|
if (process.exitValue() != 0)
|
||||||
|
println "Command $cmd exited with non-zero result code."
|
||||||
|
if (checkExit) assert process.exitValue() == 0 : "Not ignoring failed command." }
|
||||||
|
|
||||||
|
def shell(List<List<String>> cmds, File workingDir) {
|
||||||
|
cmds.each {
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(it)
|
||||||
|
pb.directory(workingDir)
|
||||||
|
pb.start().waitForProcessOutput(System.out, System.err) } }
|
||||||
|
|
||||||
|
def spawn(String... cmd) { spawn(cmd, null) }
|
||||||
|
def spawn(List<String> cmd, File workingDir) { spawn(cmd as String[], workingDir) }
|
||||||
|
def spawn(String[] cmd, File workingDir) {
|
||||||
|
def pb = new ProcessBuilder(cmd)
|
||||||
|
if (workingDir) pb.directory(workingDir)
|
||||||
|
def process = pb.start() }
|
||||||
|
|
||||||
|
|
||||||
|
18
resources/main/WEB-INF/classes/logback.groovy
Normal file
18
resources/main/WEB-INF/classes/logback.groovy
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import ch.qos.logback.core.*;
|
||||||
|
import ch.qos.logback.core.encoder.*;
|
||||||
|
import ch.qos.logback.core.read.*;
|
||||||
|
import ch.qos.logback.core.rolling.*;
|
||||||
|
import ch.qos.logback.core.status.*;
|
||||||
|
import ch.qos.logback.classic.net.*;
|
||||||
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
|
|
||||||
|
|
||||||
|
appender("STDOUT", ConsoleAppender) {
|
||||||
|
encoder(PatternLayoutEncoder) {
|
||||||
|
pattern = "%level %logger - %msg%n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root(INFO, ["STDOUT"])
|
||||||
|
logger('com.jdbernard', INFO)
|
||||||
|
|
33
shell.gradle
33
shell.gradle
@ -1,33 +0,0 @@
|
|||||||
// ## Utility methods for working with processes.
|
|
||||||
|
|
||||||
def shell_(List<String> cmd) { shell(cmd, null, false) }
|
|
||||||
def shell_(String... cmd) { shell(cmd, null, false) }
|
|
||||||
def shell(String... cmd) { shell(cmd, null, true) }
|
|
||||||
|
|
||||||
def shell(List<String> cmd, File workingDir, boolean checkExit) {
|
|
||||||
shell(cmd as String[], workingDir, checkExit) }
|
|
||||||
|
|
||||||
def shell(String[] cmd, File workingDir, boolean checkExit) {
|
|
||||||
def pb = new ProcessBuilder(cmd)
|
|
||||||
if (workingDir) pb.directory(workingDir)
|
|
||||||
def process = pb.start()
|
|
||||||
process.waitForProcessOutput(System.out, System.err)
|
|
||||||
|
|
||||||
if (process.exitValue() != 0)
|
|
||||||
println "Command $cmd exited with non-zero result code."
|
|
||||||
if (checkExit) assert process.exitValue() == 0 : "Not ignoring failed command." }
|
|
||||||
|
|
||||||
def shell(List<List<String>> cmds, File workingDir) {
|
|
||||||
cmds.each {
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(it)
|
|
||||||
pb.directory(workingDir)
|
|
||||||
pb.start().waitForProcessOutput(System.out, System.err) } }
|
|
||||||
|
|
||||||
def spawn(String... cmd) { spawn(cmd, null) }
|
|
||||||
def spawn(List<String> cmd, File workingDir) { spawn(cmd as String[], workingDir) }
|
|
||||||
def spawn(String[] cmd, File workingDir) {
|
|
||||||
def pb = new ProcessBuilder(cmd)
|
|
||||||
if (workingDir) pb.directory(workingDir)
|
|
||||||
def process = pb.start() }
|
|
||||||
|
|
||||||
|
|
@ -27,10 +27,7 @@ public class NLSongsDB {
|
|||||||
/// ### Common
|
/// ### Common
|
||||||
public def save(def model) {
|
public def save(def model) {
|
||||||
if (model.id > 0) return update(model)
|
if (model.id > 0) return update(model)
|
||||||
else {
|
else return create(model) }
|
||||||
if (create(model) > 0) return model
|
|
||||||
else return null } }
|
|
||||||
|
|
||||||
|
|
||||||
/// ### Services
|
/// ### Services
|
||||||
public Service findService(int id) {
|
public Service findService(int id) {
|
||||||
@ -315,7 +312,7 @@ public class NLSongsDB {
|
|||||||
return buildToken(row, user) }
|
return buildToken(row, user) }
|
||||||
|
|
||||||
public static List<String> unwrapArtists(String artists) {
|
public static List<String> unwrapArtists(String artists) {
|
||||||
return artists.split(';') as List<String> }
|
return artists.split(':') as List<String> }
|
||||||
|
|
||||||
public static String wrapArtists(List<String> artists) {
|
public static String wrapArtists(List<String> artists) {
|
||||||
return artists.join(':') }
|
return artists.join(':') }
|
||||||
|
@ -16,7 +16,7 @@ public class Service implements Serializable {
|
|||||||
Service that = (Service) thatObj
|
Service that = (Service) thatObj
|
||||||
|
|
||||||
return (this.id == that.id &&
|
return (this.id == that.id &&
|
||||||
this.date == (that.@date) &&
|
this.date == (that.localDate) &&
|
||||||
this.serviceType == that.serviceType) }
|
this.serviceType == that.serviceType) }
|
||||||
|
|
||||||
public void setDate(Date date) { this.date = LocalDate.fromDateFields(date) }
|
public void setDate(Date date) { this.date = LocalDate.fromDateFields(date) }
|
||||||
@ -26,4 +26,8 @@ public class Service implements Serializable {
|
|||||||
public Date getDate() { return this.date.toDate() }
|
public Date getDate() { return this.date.toDate() }
|
||||||
|
|
||||||
public String toString() { return "$id: $date - $serviceType" }
|
public String toString() { return "$id: $date - $serviceType" }
|
||||||
|
|
||||||
|
// Needed only because the @directFieldAccesor syntax stopped working in
|
||||||
|
// Groovy 2.4.7
|
||||||
|
private LocalDate getLocalDate() { return this.date }
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ import com.jdbernard.nlsongs.model.Song
|
|||||||
public class NLSongsContext {
|
public class NLSongsContext {
|
||||||
|
|
||||||
public static NLSongsDB songsDB
|
public static NLSongsDB songsDB
|
||||||
|
|
||||||
public static String mediaBaseUrl
|
public static String mediaBaseUrl
|
||||||
|
|
||||||
public static String makeUrl(Service service, Song song) {
|
public static String makeUrl(Service service, Song song) {
|
||||||
return mediaBaseUrl + '/' + service.@date.toString('yyyy-MM-dd') + '_' +
|
return mediaBaseUrl + '/' + service.localDate.toString('yyyy-MM-dd') + '_' +
|
||||||
service.serviceType.name().toLowerCase() + '_' +
|
service.serviceType.name().toLowerCase() + '_' +
|
||||||
song.name.replaceAll(/[\s'"\\\/\?!]/, '') + '.mp3' }
|
song.name.replaceAll(/[\s'"\\\/\?!]/, '') + '.mp3' }
|
||||||
}
|
}
|
||||||
|
@ -9,20 +9,40 @@ import com.jdbernard.nlsongs.db.NLSongsDB
|
|||||||
import com.zaxxer.hikari.HikariConfig
|
import com.zaxxer.hikari.HikariConfig
|
||||||
import com.zaxxer.hikari.HikariDataSource
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
|
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
public final class NLSongsContextListener implements ServletContextListener {
|
public final class NLSongsContextListener implements ServletContextListener {
|
||||||
|
|
||||||
|
private static final log = LoggerFactory.getLogger(NLSongsContextListener)
|
||||||
|
|
||||||
public void contextInitialized(ServletContextEvent event) {
|
public void contextInitialized(ServletContextEvent event) {
|
||||||
def context = event.servletContext
|
def context = event.servletContext
|
||||||
|
|
||||||
// Load the context configuration.
|
|
||||||
Properties props = new Properties()
|
Properties props = new Properties()
|
||||||
|
|
||||||
|
// Load configuration details from the context configuration.
|
||||||
NLSongsContextListener.getResourceAsStream(
|
NLSongsContextListener.getResourceAsStream(
|
||||||
context.getInitParameter('context.config.file')).withStream { is ->
|
context.getInitParameter('context.config.file'))
|
||||||
props.load(is) }
|
.withStream { is -> props.load(is) }
|
||||||
|
|
||||||
|
// Load database configuration
|
||||||
|
Properties dataSourceProps = new Properties()
|
||||||
|
String dbConfigFile = context.getInitParameter('datasource.config.file')
|
||||||
|
|
||||||
|
if (dbConfigFile) {
|
||||||
|
NLSongsContextListener.getResourceAsStream(dbConfigFile)
|
||||||
|
.withStream { is -> dataSourceProps.load(is) } }
|
||||||
|
|
||||||
|
// Load database configuration from environment variables (may
|
||||||
|
// override settings in file).
|
||||||
|
System.properties.keySet().findAll { it.startsWith('DB_') }.each { key ->
|
||||||
|
dataSourceProps["dataSource.${key.substring(3)}"] = System.properties[key] }
|
||||||
|
|
||||||
|
log.debug("Database configuration: {}", dataSourceProps)
|
||||||
|
|
||||||
// Create the pooled data source
|
// Create the pooled data source
|
||||||
HikariConfig hcfg = new HikariConfig(
|
HikariConfig hcfg = new HikariConfig(dataSourceProps)
|
||||||
context.getInitParameter('datasource.config.file'))
|
|
||||||
|
|
||||||
HikariDataSource hds = new HikariDataSource(hcfg)
|
HikariDataSource hds = new HikariDataSource(hcfg)
|
||||||
|
|
||||||
@ -39,6 +59,6 @@ public final class NLSongsContextListener implements ServletContextListener {
|
|||||||
// Shutdown the Songs DB instance (it will shut down the data source).
|
// Shutdown the Songs DB instance (it will shut down the data source).
|
||||||
NLSongsDB songsDB = context.getAttribute('songsDB')
|
NLSongsDB songsDB = context.getAttribute('songsDB')
|
||||||
if (songsDB) songsDB.shutdown()
|
if (songsDB) songsDB.shutdown()
|
||||||
|
|
||||||
context.removeAttribute('songsDB') }
|
context.removeAttribute('songsDB') }
|
||||||
}
|
}
|
||||||
|
@ -142,11 +142,26 @@ Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
|||||||
in with the request will be ignored.
|
in with the request will be ignored.
|
||||||
|
|
||||||
<p><h4>Reponse</h4>
|
<p><h4>Reponse</h4>
|
||||||
The newly-created song record.
|
The newly-created song record. If a value is given in the
|
||||||
|
request for the <tt>id</tt> attribute it is ignored. The
|
||||||
|
attribute for new records is determined by the service and
|
||||||
|
returned as part of the response.
|
||||||
|
|
||||||
<p><h4>Example</h4>
|
<p><h4>Example</h4>
|
||||||
<pre>
|
<pre>
|
||||||
</pre></li>
|
POST http://newlifesongs.jdbernard.com/api/v1/songs
|
||||||
|
Content-Length: 60
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"id":22,"name":"This is How We Praise Him","artists":[""]}
|
||||||
|
</pre>
|
||||||
|
<p><pre>
|
||||||
|
HTTP/1.1 201 Created
|
||||||
|
Content-Length:
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
|
||||||
|
</pre></li>
|
||||||
|
|
||||||
<li><h3><code>GET /songs/<songId></code></h3>
|
<li><h3><code>GET /songs/<songId></code></h3>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ if (!service) { response.sendError(response.SC_NOT_FOUND); return }
|
|||||||
<meta name="referrer" content="origin">
|
<meta name="referrer" content="origin">
|
||||||
<link rel="shortcut icon" href="../images/favicon.ico">
|
<link rel="shortcut icon" href="../images/favicon.ico">
|
||||||
|
|
||||||
<title><%= service.@date.toString("yyyy-MM-dd")
|
<title><%= service.localDate.toString("yyyy-MM-dd")
|
||||||
%> (<%= service.serviceType.displayName %>) - New Life Songs Database</title>
|
%> (<%= service.serviceType.displayName %>) - New Life Songs Database</title>
|
||||||
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||||
<!--<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js"></script>-->
|
<!--<script type="application/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js"></script>-->
|
||||||
@ -38,7 +38,7 @@ if (!service) { response.sendError(response.SC_NOT_FOUND); return }
|
|||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="../">New Life Songs</a></h1>
|
<h1><a href="../">New Life Songs</a></h1>
|
||||||
<h2 class=service-desc><%= service.@date.toString("yyyy-MM-dd") %>: (<%=
|
<h2 class=service-desc><%= service.localDate.toString("yyyy-MM-dd") %>: (<%=
|
||||||
service.description ?: service.serviceType.displayName %>)</h2>
|
service.description ?: service.serviceType.displayName %>)</h2>
|
||||||
|
|
||||||
<nav><ul>
|
<nav><ul>
|
||||||
|
@ -44,7 +44,7 @@ songsDB = NLSongsContext.songsDB
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% songsDB.findAllServices().sort { it.date }.reverse().each { service -> %>
|
<% songsDB.findAllServices().sort { it.date }.reverse().each { service -> %>
|
||||||
<tr><td class=date><a href="../service/<%= service.id %>"><%=
|
<tr><td class=date><a href="../service/<%= service.id %>"><%=
|
||||||
service.@date.toString("yyyy-MM-dd") %></a></td>
|
service.localDate.toString("yyyy-MM-dd") %></a></td>
|
||||||
<td class=service-type><%= service.description ?:
|
<td class=service-type><%= service.description ?:
|
||||||
service.serviceType.displayName %></td></tr><% } %>
|
service.serviceType.displayName %></td></tr><% } %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -57,7 +57,8 @@ songsDB = NLSongsContext.songsDB
|
|||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
window.onload = function() { \$("#services-table").
|
window.onload = function() { \$("#services-table").
|
||||||
dataTable({ "paging": false }); };
|
dataTable({ "paging": false,
|
||||||
|
"order": [[0, "desc"]]}); };
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -67,7 +67,7 @@ if (!song) { response.sendError(response.SC_NOT_FOUND); return }
|
|||||||
sort { it.svc.date }.each { row -> %>
|
sort { it.svc.date }.each { row -> %>
|
||||||
<tr><td class=actions><a href='<%= NLSongsContext.makeUrl(row.svc, song) %>'><i class="fa fa-download"></i></a></td>
|
<tr><td class=actions><a href='<%= NLSongsContext.makeUrl(row.svc, song) %>'><i class="fa fa-download"></i></a></td>
|
||||||
<td class=performance-date><a href='../service/<%= row.svc.id %>'><%=
|
<td class=performance-date><a href='../service/<%= row.svc.id %>'><%=
|
||||||
row.svc.@date.toString("yyyy-MM-dd") %></a></td>
|
row.svc.localDate.toString("yyyy-MM-dd") %></a></td>
|
||||||
<td class=service-type><%= row.svc.serviceType.displayName %></td>
|
<td class=service-type><%= row.svc.serviceType.displayName %></td>
|
||||||
<td class=not-small><%= row.perf.leader ?: "" %></td>
|
<td class=not-small><%= row.perf.leader ?: "" %></td>
|
||||||
<td class=not-small><%= row.perf.pianist ?: "" %></td>
|
<td class=not-small><%= row.perf.pianist ?: "" %></td>
|
||||||
|
@ -5,8 +5,7 @@ import com.jdbernard.nlsongs.model.*
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
sdf = new SimpleDateFormat('yyyy-MM-dd')
|
sdf = new SimpleDateFormat('yyyy-MM-dd')
|
||||||
hcfg = new
|
hcfg = new HikariConfig("/home/jdbernard/projects/new-life-songs/src/main/webapp/WEB-INF/classes/datasource.properties")
|
||||||
HikariConfig("/home/jdbernard/projects/new-life-songs/src/main/webapp/WEB-INF/classes/datasource.properties")
|
|
||||||
|
|
||||||
makeService = { svcRow ->
|
makeService = { svcRow ->
|
||||||
Service svc = new Service()
|
Service svc = new Service()
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jdbernard.nlsongs.rest
|
package com.jdbernard.nlsongs.rest
|
||||||
|
|
||||||
import com.jdbernard.net.HttpContext
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package com.jdbernard.nlsongs.db
|
|
||||||
|
|
||||||
public class GenerateQueries {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, Map<String, String> > generateQueries(String ddl) {
|
|
||||||
|
|
||||||
def tables = [:]
|
|
||||||
|
|
||||||
// Find the table definitions
|
|
||||||
String tableRegex = /(?ms)(?:CREATE TABLE (?:IF NOT EXISTS )?([^\s]+) \(([^\s]+);.+?)+/
|
|
||||||
|
|
||||||
ddl.eachMatch(tableRegex) { matchGroups ->
|
|
||||||
String tableName = matchGroups[1]
|
|
||||||
|
|
||||||
// Parse the column definitions.
|
|
||||||
|
|
||||||
// Create new record insert statements.
|
|
||||||
|
|
||||||
// Create insert queries.
|
|
||||||
|
|
||||||
// Create update queries.
|
|
||||||
|
|
||||||
// Create delete queries.
|
|
||||||
|
|
||||||
// Create ID lookup queries.
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
#Tue Apr 14 15:12:24 CDT 2015
|
#Sat Dec 17 21:50:15 CST 2016
|
||||||
major=2
|
major=2
|
||||||
version.release=false
|
version.release=true
|
||||||
minor=2
|
minor=5
|
||||||
build=13
|
build=0
|
||||||
|
Reference in New Issue
Block a user